1/* 2 * Copyright (c) 2014 Broadcom Corporation 3 * 4 * Permission to use, copy, modify, and/or distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY 11 * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION 13 * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN 14 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17#include <linux/netdevice.h> 18 19#include <brcm_hw_ids.h> 20#include "core.h" 21#include "bus.h" 22#include "debug.h" 23#include "fwil.h" 24#include "feature.h" 25 26/* 27 * expand feature list to array of feature strings. 28 */ 29#define BRCMF_FEAT_DEF(_f) \ 30 #_f, 31static const char *brcmf_feat_names[] = { 32 BRCMF_FEAT_LIST 33}; 34#undef BRCMF_FEAT_DEF 35 36#ifdef DEBUG 37/* 38 * expand quirk list to array of quirk strings. 39 */ 40#define BRCMF_QUIRK_DEF(_q) \ 41 #_q, 42static const char * const brcmf_quirk_names[] = { 43 BRCMF_QUIRK_LIST 44}; 45#undef BRCMF_QUIRK_DEF 46 47/** 48 * brcmf_feat_debugfs_read() - expose feature info to debugfs. 49 * 50 * @seq: sequence for debugfs entry. 51 * @data: raw data pointer. 52 */ 53static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data) 54{ 55 struct brcmf_bus *bus_if = dev_get_drvdata(seq->private); 56 u32 feats = bus_if->drvr->feat_flags; 57 u32 quirks = bus_if->drvr->chip_quirks; 58 int id; 59 60 seq_printf(seq, "Features: %08x\n", feats); 61 for (id = 0; id < BRCMF_FEAT_LAST; id++) 62 if (feats & BIT(id)) 63 seq_printf(seq, "\t%s\n", brcmf_feat_names[id]); 64 seq_printf(seq, "\nQuirks: %08x\n", quirks); 65 for (id = 0; id < BRCMF_FEAT_QUIRK_LAST; id++) 66 if (quirks & BIT(id)) 67 seq_printf(seq, "\t%s\n", brcmf_quirk_names[id]); 68 return 0; 69} 70#else 71static int brcmf_feat_debugfs_read(struct seq_file *seq, void *data) 72{ 73 return 0; 74} 75#endif /* DEBUG */ 76 77/** 78 * brcmf_feat_iovar_int_get() - determine feature through iovar query. 79 * 80 * @ifp: interface to query. 81 * @id: feature id. 82 * @name: iovar name. 83 */ 84static void brcmf_feat_iovar_int_get(struct brcmf_if *ifp, 85 enum brcmf_feat_id id, char *name) 86{ 87 u32 data; 88 int err; 89 90 err = brcmf_fil_iovar_int_get(ifp, name, &data); 91 if (err == 0) { 92 brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); 93 ifp->drvr->feat_flags |= BIT(id); 94 } else { 95 brcmf_dbg(TRACE, "%s feature check failed: %d\n", 96 brcmf_feat_names[id], err); 97 } 98} 99 100/** 101 * brcmf_feat_iovar_int_set() - determine feature through iovar set. 102 * 103 * @ifp: interface to query. 104 * @id: feature id. 105 * @name: iovar name. 106 */ 107static void brcmf_feat_iovar_int_set(struct brcmf_if *ifp, 108 enum brcmf_feat_id id, char *name, u32 val) 109{ 110 int err; 111 112 err = brcmf_fil_iovar_int_set(ifp, name, val); 113 if (err == 0) { 114 brcmf_dbg(INFO, "enabling feature: %s\n", brcmf_feat_names[id]); 115 ifp->drvr->feat_flags |= BIT(id); 116 } else { 117 brcmf_dbg(TRACE, "%s feature check failed: %d\n", 118 brcmf_feat_names[id], err); 119 } 120} 121 122void brcmf_feat_attach(struct brcmf_pub *drvr) 123{ 124 struct brcmf_if *ifp = drvr->iflist[0]; 125 126 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_MCHAN, "mchan"); 127 if (drvr->bus_if->wowl_supported) 128 brcmf_feat_iovar_int_get(ifp, BRCMF_FEAT_WOWL, "wowl"); 129 if (drvr->bus_if->chip != BRCM_CC_43362_CHIP_ID) 130 brcmf_feat_iovar_int_set(ifp, BRCMF_FEAT_MBSS, "mbss", 0); 131 132 /* set chip related quirks */ 133 switch (drvr->bus_if->chip) { 134 case BRCM_CC_43236_CHIP_ID: 135 drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_AUTO_AUTH); 136 break; 137 case BRCM_CC_4329_CHIP_ID: 138 drvr->chip_quirks |= BIT(BRCMF_FEAT_QUIRK_NEED_MPC); 139 break; 140 default: 141 /* no quirks */ 142 break; 143 } 144 145 brcmf_debugfs_add_entry(drvr, "features", brcmf_feat_debugfs_read); 146} 147 148bool brcmf_feat_is_enabled(struct brcmf_if *ifp, enum brcmf_feat_id id) 149{ 150 return (ifp->drvr->feat_flags & BIT(id)); 151} 152 153bool brcmf_feat_is_quirk_enabled(struct brcmf_if *ifp, 154 enum brcmf_feat_quirk quirk) 155{ 156 return (ifp->drvr->chip_quirks & BIT(quirk)); 157} 158