2
0
mirror of https://github.com/edk2-porting/linux-next.git synced 2024-12-16 01:04:08 +08:00

Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless

John says:

--------------------
I apologize for not having sent this sooner.  FWIW, I was in a car
somewhere between Illinois and North Carolina for most of the day
Sunday and Monday... :-)

This is (obviously) the last non-fix pull request for wireless bits
intended for 3.5.  It includes AP support for mwifiex, a variety of HCI
and other updates for NFC, some brcmfmac and brcmsmac refactoring,
a large batch of ssb and bcma updates, a batch of ath6kl updates,
some cfg80211 and mac80211 updates/refactoring from Johannes Berg,
a rather large collection of Bluetooth updates by way of Gustavo,
and a variety of other bits here and there.
--------------------

Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
David S. Miller 2012-05-22 16:07:23 -04:00
commit c3719a1ef5
173 changed files with 6623 additions and 5504 deletions

View File

@ -534,6 +534,18 @@ Who: Kees Cook <keescook@chromium.org>
----------------------------
What: Removing the pn544 raw driver.
When: 3.6
Why: With the introduction of the NFC HCI and SHDL kernel layers, pn544.c
is being replaced by pn544_hci.c which is accessible through the netlink
and socket NFC APIs. Moreover, pn544.c is outdated and does not seem to
work properly with the latest Android stacks.
Having 2 drivers for the same hardware is confusing and as such we
should only keep the one following the kernel NFC APIs.
Who: Samuel Ortiz <sameo@linux.intel.com>
----------------------------
What: setitimer accepts user NULL pointer (value)
When: 3.6
Why: setitimer is not returning -EFAULT if user pointer is NULL. This

View File

@ -22,9 +22,9 @@ response to arrive.
HCI events can also be received from the host controller. They will be handled
and a translation will be forwarded to NFC Core as needed.
HCI uses 2 execution contexts:
- one if for executing commands : nfc_hci_msg_tx_work(). Only one command
- one for executing commands : nfc_hci_msg_tx_work(). Only one command
can be executing at any given moment.
- one if for dispatching received events and responses : nfc_hci_msg_rx_work()
- one for dispatching received events and commands : nfc_hci_msg_rx_work().
HCI Session initialization:
---------------------------
@ -52,18 +52,42 @@ entry points:
struct nfc_hci_ops {
int (*open)(struct nfc_hci_dev *hdev);
void (*close)(struct nfc_hci_dev *hdev);
int (*hci_ready) (struct nfc_hci_dev *hdev);
int (*xmit)(struct nfc_hci_dev *hdev, struct sk_buff *skb);
int (*start_poll)(struct nfc_hci_dev *hdev, u32 protocols);
int (*target_from_gate)(struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
int (*complete_target_discovered) (struct nfc_hci_dev *hdev, u8 gate,
struct nfc_target *target);
int (*data_exchange) (struct nfc_hci_dev *hdev,
struct nfc_target *target,
struct sk_buff *skb, struct sk_buff **res_skb);
int (*check_presence)(struct nfc_hci_dev *hdev,
struct nfc_target *target);
};
open() and close() shall turn the hardware on and off. xmit() shall simply
write a frame to the chip. start_poll() is an optional entrypoint that shall
set the hardware in polling mode. This must be implemented only if the hardware
uses proprietary gates or a mechanism slightly different from the HCI standard.
target_from_gate() is another optional entrypoint to return the protocols
- open() and close() shall turn the hardware on and off.
- hci_ready() is an optional entry point that is called right after the hci
session has been set up. The driver can use it to do additional initialization
that must be performed using HCI commands.
- xmit() shall simply write a frame to the chip.
- start_poll() is an optional entrypoint that shall set the hardware in polling
mode. This must be implemented only if the hardware uses proprietary gates or a
mechanism slightly different from the HCI standard.
- target_from_gate() is an optional entrypoint to return the nfc protocols
corresponding to a proprietary gate.
- complete_target_discovered() is an optional entry point to let the driver
perform additional proprietary processing necessary to auto activate the
discovered target.
- data_exchange() must be implemented by the driver if proprietary HCI commands
are required to send data to the tag. Some tag types will require custom
commands, others can be written to using the standard HCI commands. The driver
can check the tag type and either do proprietary processing, or return 1 to ask
for standard processing.
- check_presence() is an optional entry point that will be called regularly
by the core to check that an activated tag is still in the field. If this is
not implemented, the core will not be able to push tag_lost events to the user
space
On the rx path, the driver is responsible to push incoming HCP frames to HCI
using nfc_hci_recv_frame(). HCI will take care of re-aggregation and handling
@ -99,7 +123,8 @@ fast, cannot sleep. stores incoming frames into an shdlc rx queue
handles shdlc rx & tx queues. Dispatches HCI cmd responses.
- HCI Tx Cmd worker (MSGTXWQ)
Serialize execution of HCI commands. Complete execution in case of resp timeout.
Serializes execution of HCI commands. Completes execution in case of response
timeout.
- HCI Rx worker (MSGRXWQ)
Dispatches incoming HCI commands or events.
@ -133,11 +158,11 @@ able to complete the command with a timeout error if no response arrive.
SMW context gets scheduled and invokes nfc_shdlc_sm_work(). This function
handles shdlc framing in and out. It uses the driver xmit to send frames and
receives incoming frames in an skb queue filled from the driver IRQ handler.
SHDLC I(nformation) frames payload are HCP fragments. They are agregated to
SHDLC I(nformation) frames payload are HCP fragments. They are aggregated to
form complete HCI frames, which can be a response, command, or event.
HCI Responses are dispatched immediately from this context to unblock
waiting command execution. Reponse processing involves invoking the completion
waiting command execution. Response processing involves invoking the completion
callback that was provided by nfc_hci_msg_tx_work() when it sent the command.
The completion callback will then wake the syscall context.

View File

@ -90,6 +90,7 @@ static int bcm47xx_get_sprom_ssb(struct ssb_bus *bus, struct ssb_sprom *out)
char prefix[10];
if (bus->bustype == SSB_BUSTYPE_PCI) {
memset(out, 0, sizeof(struct ssb_sprom));
snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
bus->host_pci->bus->number + 1,
PCI_SLOT(bus->host_pci->devfn));
@ -109,15 +110,9 @@ static int bcm47xx_get_invariants(struct ssb_bus *bus,
/* Fill boardinfo structure */
memset(&(iv->boardinfo), 0 , sizeof(struct ssb_boardinfo));
if (nvram_getenv("boardvendor", buf, sizeof(buf)) >= 0)
iv->boardinfo.vendor = (u16)simple_strtoul(buf, NULL, 0);
else
iv->boardinfo.vendor = SSB_BOARDVENDOR_BCM;
if (nvram_getenv("boardtype", buf, sizeof(buf)) >= 0)
iv->boardinfo.type = (u16)simple_strtoul(buf, NULL, 0);
if (nvram_getenv("boardrev", buf, sizeof(buf)) >= 0)
iv->boardinfo.rev = (u16)simple_strtoul(buf, NULL, 0);
bcm47xx_fill_ssb_boardinfo(&iv->boardinfo, NULL);
memset(&iv->sprom, 0, sizeof(struct ssb_sprom));
bcm47xx_fill_sprom(&iv->sprom, NULL);
if (nvram_getenv("cardbus", buf, sizeof(buf)) >= 0)
@ -166,12 +161,14 @@ static int bcm47xx_get_sprom_bcma(struct bcma_bus *bus, struct ssb_sprom *out)
switch (bus->hosttype) {
case BCMA_HOSTTYPE_PCI:
memset(out, 0, sizeof(struct ssb_sprom));
snprintf(prefix, sizeof(prefix), "pci/%u/%u/",
bus->host_pci->bus->number + 1,
PCI_SLOT(bus->host_pci->devfn));
bcm47xx_fill_sprom(out, prefix);
return 0;
case BCMA_HOSTTYPE_SOC:
memset(out, 0, sizeof(struct ssb_sprom));
bcm47xx_fill_sprom_ethernet(out, NULL);
core = bcma_find_core(bus, BCMA_CORE_80211);
if (core) {
@ -197,6 +194,8 @@ static void __init bcm47xx_register_bcma(void)
err = bcma_host_soc_register(&bcm47xx_bus.bcma);
if (err)
panic("Failed to initialize BCMA bus (err %d)", err);
bcm47xx_fill_bcma_boardinfo(&bcm47xx_bus.bcma.bus.boardinfo, NULL);
}
#endif

View File

@ -165,6 +165,8 @@ static void bcm47xx_fill_sprom_r1234589(struct ssb_sprom *sprom,
const char *prefix)
{
nvram_read_u16(prefix, NULL, "boardrev", &sprom->board_rev, 0);
if (!sprom->board_rev)
nvram_read_u16(NULL, NULL, "boardrev", &sprom->board_rev, 0);
nvram_read_u16(prefix, NULL, "boardnum", &sprom->board_num, 0);
nvram_read_u8(prefix, NULL, "ledbh0", &sprom->gpio0, 0xff);
nvram_read_u8(prefix, NULL, "ledbh1", &sprom->gpio1, 0xff);
@ -555,8 +557,6 @@ void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix)
void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix)
{
memset(sprom, 0, sizeof(struct ssb_sprom));
bcm47xx_fill_sprom_ethernet(sprom, prefix);
nvram_read_u8(prefix, NULL, "sromrev", &sprom->revision, 0);
@ -618,3 +618,27 @@ void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix)
bcm47xx_fill_sprom_r1(sprom, prefix);
}
}
#ifdef CONFIG_BCM47XX_SSB
void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo,
const char *prefix)
{
nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0);
if (!boardinfo->vendor)
boardinfo->vendor = SSB_BOARDVENDOR_BCM;
nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0);
}
#endif
#ifdef CONFIG_BCM47XX_BCMA
void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo,
const char *prefix)
{
nvram_read_u16(prefix, NULL, "boardvendor", &boardinfo->vendor, 0);
if (!boardinfo->vendor)
boardinfo->vendor = SSB_BOARDVENDOR_BCM;
nvram_read_u16(prefix, NULL, "boardtype", &boardinfo->type, 0);
}
#endif

View File

@ -47,4 +47,13 @@ extern enum bcm47xx_bus_type bcm47xx_bus_type;
void bcm47xx_fill_sprom(struct ssb_sprom *sprom, const char *prefix);
void bcm47xx_fill_sprom_ethernet(struct ssb_sprom *sprom, const char *prefix);
#ifdef CONFIG_BCM47XX_SSB
void bcm47xx_fill_ssb_boardinfo(struct ssb_boardinfo *boardinfo,
const char *prefix);
#endif
#ifdef CONFIG_BCM47XX_BCMA
void bcm47xx_fill_bcma_boardinfo(struct bcma_boardinfo *boardinfo,
const char *prefix);
#endif
#endif /* __ASM_BCM47XX_H */

View File

@ -30,6 +30,7 @@ void bcma_core_disable(struct bcma_device *core, u32 flags)
udelay(10);
bcma_awrite32(core, BCMA_RESET_CTL, BCMA_RESET_CTL_RESET);
bcma_aread32(core, BCMA_RESET_CTL);
udelay(1);
}
EXPORT_SYMBOL_GPL(bcma_core_disable);
@ -77,7 +78,7 @@ void bcma_core_set_clockmode(struct bcma_device *core,
pr_err("HT force timeout\n");
break;
case BCMA_CLKMODE_DYNAMIC:
pr_warn("Dynamic clockmode not supported yet!\n");
bcma_set32(core, BCMA_CLKCTLST, ~BCMA_CLKCTLST_FORCEHT);
break;
}
}

View File

@ -24,14 +24,12 @@ u32 bcma_pcie_read(struct bcma_drv_pci *pc, u32 address)
return pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_DATA);
}
#if 0
static void bcma_pcie_write(struct bcma_drv_pci *pc, u32 address, u32 data)
{
pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_ADDR, address);
pcicore_read32(pc, BCMA_CORE_PCI_PCIEIND_ADDR);
pcicore_write32(pc, BCMA_CORE_PCI_PCIEIND_DATA, data);
}
#endif
static void bcma_pcie_mdio_set_phy(struct bcma_drv_pci *pc, u8 phy)
{
@ -170,13 +168,50 @@ static void bcma_pcicore_serdes_workaround(struct bcma_drv_pci *pc)
tmp & ~BCMA_CORE_PCI_PLL_CTRL_FREQDET_EN);
}
static void bcma_core_pci_fixcfg(struct bcma_drv_pci *pc)
{
struct bcma_device *core = pc->core;
u16 val16, core_index;
uint regoff;
regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_PI_OFFSET);
core_index = (u16)core->core_index;
val16 = pcicore_read16(pc, regoff);
if (((val16 & BCMA_CORE_PCI_SPROM_PI_MASK) >> BCMA_CORE_PCI_SPROM_PI_SHIFT)
!= core_index) {
val16 = (core_index << BCMA_CORE_PCI_SPROM_PI_SHIFT) |
(val16 & ~BCMA_CORE_PCI_SPROM_PI_MASK);
pcicore_write16(pc, regoff, val16);
}
}
/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void bcma_core_pci_config_fixup(struct bcma_drv_pci *pc)
{
u16 val16;
uint regoff;
regoff = BCMA_CORE_PCI_SPROM(BCMA_CORE_PCI_SPROM_MISC_CONFIG);
val16 = pcicore_read16(pc, regoff);
if (!(val16 & BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST)) {
val16 |= BCMA_CORE_PCI_SPROM_L23READY_EXIT_NOPERST;
pcicore_write16(pc, regoff, val16);
}
}
/**************************************************
* Init.
**************************************************/
static void __devinit bcma_core_pci_clientmode_init(struct bcma_drv_pci *pc)
{
bcma_core_pci_fixcfg(pc);
bcma_pcicore_serdes_workaround(pc);
bcma_core_pci_config_fixup(pc);
}
void __devinit bcma_core_pci_init(struct bcma_drv_pci *pc)
@ -224,3 +259,17 @@ out:
return err;
}
EXPORT_SYMBOL_GPL(bcma_core_pci_irq_ctl);
void bcma_core_pci_extend_L1timer(struct bcma_drv_pci *pc, bool extend)
{
u32 w;
w = bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG);
if (extend)
w |= BCMA_CORE_PCI_ASPMTIMER_EXTEND;
else
w &= ~BCMA_CORE_PCI_ASPMTIMER_EXTEND;
bcma_pcie_write(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG, w);
bcma_pcie_read(pc, BCMA_CORE_PCI_DLLP_PMTHRESHREG);
}
EXPORT_SYMBOL_GPL(bcma_core_pci_extend_L1timer);

View File

@ -119,7 +119,7 @@ static int bcma_extpci_read_config(struct bcma_drv_pci *pc, unsigned int dev,
if (unlikely(!addr))
goto out;
err = -ENOMEM;
mmio = ioremap_nocache(addr, len);
mmio = ioremap_nocache(addr, sizeof(val));
if (!mmio)
goto out;
@ -171,7 +171,7 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
addr = pc->core->addr + BCMA_CORE_PCI_PCICFG0;
addr |= (func << 8);
addr |= (off & 0xfc);
mmio = ioremap_nocache(addr, len);
mmio = ioremap_nocache(addr, sizeof(val));
if (!mmio)
goto out;
}
@ -180,7 +180,7 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
if (unlikely(!addr))
goto out;
err = -ENOMEM;
mmio = ioremap_nocache(addr, len);
mmio = ioremap_nocache(addr, sizeof(val));
if (!mmio)
goto out;
@ -491,8 +491,8 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
/* Ok, ready to run, register it to the system.
* The following needs change, if we want to port hostmode
* to non-MIPS platform. */
io_map_base = (unsigned long)ioremap_nocache(BCMA_SOC_PCI_MEM,
0x04000000);
io_map_base = (unsigned long)ioremap_nocache(pc_host->mem_resource.start,
resource_size(&pc_host->mem_resource));
pc_host->pci_controller.io_map_base = io_map_base;
set_io_port_base(pc_host->pci_controller.io_map_base);
/* Give some time to the PCI controller to configure itself with the new

View File

@ -201,6 +201,9 @@ static int __devinit bcma_host_pci_probe(struct pci_dev *dev,
bus->hosttype = BCMA_HOSTTYPE_PCI;
bus->ops = &bcma_host_pci_ops;
bus->boardinfo.vendor = bus->host_pci->subsystem_vendor;
bus->boardinfo.type = bus->host_pci->subsystem_device;
/* Register */
err = bcma_bus_register(bus);
if (err)
@ -222,7 +225,7 @@ err_kfree_bus:
return err;
}
static void bcma_host_pci_remove(struct pci_dev *dev)
static void __devexit bcma_host_pci_remove(struct pci_dev *dev)
{
struct bcma_bus *bus = pci_get_drvdata(dev);
@ -277,7 +280,7 @@ static struct pci_driver bcma_pci_bridge_driver = {
.name = "bcma-pci-bridge",
.id_table = bcma_pci_bridge_tbl,
.probe = bcma_host_pci_probe,
.remove = bcma_host_pci_remove,
.remove = __devexit_p(bcma_host_pci_remove),
.driver.pm = BCMA_PM_OPS,
};

View File

@ -19,7 +19,14 @@ struct bcma_device_id_name {
u16 id;
const char *name;
};
struct bcma_device_id_name bcma_device_names[] = {
static const struct bcma_device_id_name bcma_arm_device_names[] = {
{ BCMA_CORE_ARM_1176, "ARM 1176" },
{ BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
{ BCMA_CORE_ARM_CM3, "ARM CM3" },
};
static const struct bcma_device_id_name bcma_bcm_device_names[] = {
{ BCMA_CORE_OOB_ROUTER, "OOB Router" },
{ BCMA_CORE_INVALID, "Invalid" },
{ BCMA_CORE_CHIPCOMMON, "ChipCommon" },
@ -27,7 +34,6 @@ struct bcma_device_id_name bcma_device_names[] = {
{ BCMA_CORE_SRAM, "SRAM" },
{ BCMA_CORE_SDRAM, "SDRAM" },
{ BCMA_CORE_PCI, "PCI" },
{ BCMA_CORE_MIPS, "MIPS" },
{ BCMA_CORE_ETHERNET, "Fast Ethernet" },
{ BCMA_CORE_V90, "V90" },
{ BCMA_CORE_USB11_HOSTDEV, "USB 1.1 Hostdev" },
@ -44,7 +50,6 @@ struct bcma_device_id_name bcma_device_names[] = {
{ BCMA_CORE_PHY_A, "PHY A" },
{ BCMA_CORE_PHY_B, "PHY B" },
{ BCMA_CORE_PHY_G, "PHY G" },
{ BCMA_CORE_MIPS_3302, "MIPS 3302" },
{ BCMA_CORE_USB11_HOST, "USB 1.1 Host" },
{ BCMA_CORE_USB11_DEV, "USB 1.1 Device" },
{ BCMA_CORE_USB20_HOST, "USB 2.0 Host" },
@ -58,15 +63,11 @@ struct bcma_device_id_name bcma_device_names[] = {
{ BCMA_CORE_PHY_N, "PHY N" },
{ BCMA_CORE_SRAM_CTL, "SRAM Controller" },
{ BCMA_CORE_MINI_MACPHY, "Mini MACPHY" },
{ BCMA_CORE_ARM_1176, "ARM 1176" },
{ BCMA_CORE_ARM_7TDMI, "ARM 7TDMI" },
{ BCMA_CORE_PHY_LP, "PHY LP" },
{ BCMA_CORE_PMU, "PMU" },
{ BCMA_CORE_PHY_SSN, "PHY SSN" },
{ BCMA_CORE_SDIO_DEV, "SDIO Device" },
{ BCMA_CORE_ARM_CM3, "ARM CM3" },
{ BCMA_CORE_PHY_HT, "PHY HT" },
{ BCMA_CORE_MIPS_74K, "MIPS 74K" },
{ BCMA_CORE_MAC_GBIT, "GBit MAC" },
{ BCMA_CORE_DDR12_MEM_CTL, "DDR1/DDR2 Memory Controller" },
{ BCMA_CORE_PCIE_RC, "PCIe Root Complex" },
@ -79,16 +80,41 @@ struct bcma_device_id_name bcma_device_names[] = {
{ BCMA_CORE_SHIM, "SHIM" },
{ BCMA_CORE_DEFAULT, "Default" },
};
const char *bcma_device_name(struct bcma_device_id *id)
{
int i;
if (id->manuf == BCMA_MANUF_BCM) {
for (i = 0; i < ARRAY_SIZE(bcma_device_names); i++) {
if (bcma_device_names[i].id == id->id)
return bcma_device_names[i].name;
}
static const struct bcma_device_id_name bcma_mips_device_names[] = {
{ BCMA_CORE_MIPS, "MIPS" },
{ BCMA_CORE_MIPS_3302, "MIPS 3302" },
{ BCMA_CORE_MIPS_74K, "MIPS 74K" },
};
static const char *bcma_device_name(const struct bcma_device_id *id)
{
const struct bcma_device_id_name *names;
int size, i;
/* search manufacturer specific names */
switch (id->manuf) {
case BCMA_MANUF_ARM:
names = bcma_arm_device_names;
size = ARRAY_SIZE(bcma_arm_device_names);
break;
case BCMA_MANUF_BCM:
names = bcma_bcm_device_names;
size = ARRAY_SIZE(bcma_bcm_device_names);
break;
case BCMA_MANUF_MIPS:
names = bcma_mips_device_names;
size = ARRAY_SIZE(bcma_mips_device_names);
break;
default:
return "UNKNOWN";
}
for (i = 0; i < size; i++) {
if (names[i].id == id->id)
return names[i].name;
}
return "UNKNOWN";
}

View File

@ -181,6 +181,22 @@ static int bcma_sprom_valid(const u16 *sprom)
#define SPEX(_field, _offset, _mask, _shift) \
bus->sprom._field = ((sprom[SPOFF(_offset)] & (_mask)) >> (_shift))
#define SPEX32(_field, _offset, _mask, _shift) \
bus->sprom._field = ((((u32)sprom[SPOFF((_offset)+2)] << 16 | \
sprom[SPOFF(_offset)]) & (_mask)) >> (_shift))
#define SPEX_ARRAY8(_field, _offset, _mask, _shift) \
do { \
SPEX(_field[0], _offset + 0, _mask, _shift); \
SPEX(_field[1], _offset + 2, _mask, _shift); \
SPEX(_field[2], _offset + 4, _mask, _shift); \
SPEX(_field[3], _offset + 6, _mask, _shift); \
SPEX(_field[4], _offset + 8, _mask, _shift); \
SPEX(_field[5], _offset + 10, _mask, _shift); \
SPEX(_field[6], _offset + 12, _mask, _shift); \
SPEX(_field[7], _offset + 14, _mask, _shift); \
} while (0)
static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
{
u16 v, o;
@ -243,7 +259,8 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
SPEX(boardflags2_lo, SSB_SPROM8_BFL2LO, ~0, 0);
SPEX(boardflags2_hi, SSB_SPROM8_BFL2HI, ~0, 0);
SPEX(country_code, SSB_SPROM8_CCODE, ~0, 0);
SPEX(alpha2[0], SSB_SPROM8_CCODE, 0xff00, 8);
SPEX(alpha2[1], SSB_SPROM8_CCODE, 0x00ff, 0);
/* Extract cores power info info */
for (i = 0; i < ARRAY_SIZE(pwr_info_offset); i++) {
@ -298,6 +315,136 @@ static void bcma_sprom_extract_r8(struct bcma_bus *bus, const u16 *sprom)
SSB_SROM8_FEM_TR_ISO_SHIFT);
SPEX(fem.ghz5.antswlut, SSB_SPROM8_FEM5G, SSB_SROM8_FEM_ANTSWLUT,
SSB_SROM8_FEM_ANTSWLUT_SHIFT);
SPEX(ant_available_a, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_A,
SSB_SPROM8_ANTAVAIL_A_SHIFT);
SPEX(ant_available_bg, SSB_SPROM8_ANTAVAIL, SSB_SPROM8_ANTAVAIL_BG,
SSB_SPROM8_ANTAVAIL_BG_SHIFT);
SPEX(maxpwr_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_MAXP_BG_MASK, 0);
SPEX(itssi_bg, SSB_SPROM8_MAXP_BG, SSB_SPROM8_ITSSI_BG,
SSB_SPROM8_ITSSI_BG_SHIFT);
SPEX(maxpwr_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_MAXP_A_MASK, 0);
SPEX(itssi_a, SSB_SPROM8_MAXP_A, SSB_SPROM8_ITSSI_A,
SSB_SPROM8_ITSSI_A_SHIFT);
SPEX(maxpwr_ah, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AH_MASK, 0);
SPEX(maxpwr_al, SSB_SPROM8_MAXP_AHL, SSB_SPROM8_MAXP_AL_MASK,
SSB_SPROM8_MAXP_AL_SHIFT);
SPEX(gpio0, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P0, 0);
SPEX(gpio1, SSB_SPROM8_GPIOA, SSB_SPROM8_GPIOA_P1,
SSB_SPROM8_GPIOA_P1_SHIFT);
SPEX(gpio2, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P2, 0);
SPEX(gpio3, SSB_SPROM8_GPIOB, SSB_SPROM8_GPIOB_P3,
SSB_SPROM8_GPIOB_P3_SHIFT);
SPEX(tri2g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI2G, 0);
SPEX(tri5g, SSB_SPROM8_TRI25G, SSB_SPROM8_TRI5G,
SSB_SPROM8_TRI5G_SHIFT);
SPEX(tri5gl, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GL, 0);
SPEX(tri5gh, SSB_SPROM8_TRI5GHL, SSB_SPROM8_TRI5GH,
SSB_SPROM8_TRI5GH_SHIFT);
SPEX(rxpo2g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO2G,
SSB_SPROM8_RXPO2G_SHIFT);
SPEX(rxpo5g, SSB_SPROM8_RXPO, SSB_SPROM8_RXPO5G,
SSB_SPROM8_RXPO5G_SHIFT);
SPEX(rssismf2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMF2G, 0);
SPEX(rssismc2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISMC2G,
SSB_SPROM8_RSSISMC2G_SHIFT);
SPEX(rssisav2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_RSSISAV2G,
SSB_SPROM8_RSSISAV2G_SHIFT);
SPEX(bxa2g, SSB_SPROM8_RSSIPARM2G, SSB_SPROM8_BXA2G,
SSB_SPROM8_BXA2G_SHIFT);
SPEX(rssismf5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMF5G, 0);
SPEX(rssismc5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISMC5G,
SSB_SPROM8_RSSISMC5G_SHIFT);
SPEX(rssisav5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_RSSISAV5G,
SSB_SPROM8_RSSISAV5G_SHIFT);
SPEX(bxa5g, SSB_SPROM8_RSSIPARM5G, SSB_SPROM8_BXA5G,
SSB_SPROM8_BXA5G_SHIFT);
SPEX(pa0b0, SSB_SPROM8_PA0B0, ~0, 0);
SPEX(pa0b1, SSB_SPROM8_PA0B1, ~0, 0);
SPEX(pa0b2, SSB_SPROM8_PA0B2, ~0, 0);
SPEX(pa1b0, SSB_SPROM8_PA1B0, ~0, 0);
SPEX(pa1b1, SSB_SPROM8_PA1B1, ~0, 0);
SPEX(pa1b2, SSB_SPROM8_PA1B2, ~0, 0);
SPEX(pa1lob0, SSB_SPROM8_PA1LOB0, ~0, 0);
SPEX(pa1lob1, SSB_SPROM8_PA1LOB1, ~0, 0);
SPEX(pa1lob2, SSB_SPROM8_PA1LOB2, ~0, 0);
SPEX(pa1hib0, SSB_SPROM8_PA1HIB0, ~0, 0);
SPEX(pa1hib1, SSB_SPROM8_PA1HIB1, ~0, 0);
SPEX(pa1hib2, SSB_SPROM8_PA1HIB2, ~0, 0);
SPEX(cck2gpo, SSB_SPROM8_CCK2GPO, ~0, 0);
SPEX32(ofdm2gpo, SSB_SPROM8_OFDM2GPO, ~0, 0);
SPEX32(ofdm5glpo, SSB_SPROM8_OFDM5GLPO, ~0, 0);
SPEX32(ofdm5gpo, SSB_SPROM8_OFDM5GPO, ~0, 0);
SPEX32(ofdm5ghpo, SSB_SPROM8_OFDM5GHPO, ~0, 0);
/* Extract the antenna gain values. */
SPEX(antenna_gain.a0, SSB_SPROM8_AGAIN01,
SSB_SPROM8_AGAIN0, SSB_SPROM8_AGAIN0_SHIFT);
SPEX(antenna_gain.a1, SSB_SPROM8_AGAIN01,
SSB_SPROM8_AGAIN1, SSB_SPROM8_AGAIN1_SHIFT);
SPEX(antenna_gain.a2, SSB_SPROM8_AGAIN23,
SSB_SPROM8_AGAIN2, SSB_SPROM8_AGAIN2_SHIFT);
SPEX(antenna_gain.a3, SSB_SPROM8_AGAIN23,
SSB_SPROM8_AGAIN3, SSB_SPROM8_AGAIN3_SHIFT);
SPEX(leddc_on_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_ON,
SSB_SPROM8_LEDDC_ON_SHIFT);
SPEX(leddc_off_time, SSB_SPROM8_LEDDC, SSB_SPROM8_LEDDC_OFF,
SSB_SPROM8_LEDDC_OFF_SHIFT);
SPEX(txchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_TXCHAIN,
SSB_SPROM8_TXRXC_TXCHAIN_SHIFT);
SPEX(rxchain, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_RXCHAIN,
SSB_SPROM8_TXRXC_RXCHAIN_SHIFT);
SPEX(antswitch, SSB_SPROM8_TXRXC, SSB_SPROM8_TXRXC_SWITCH,
SSB_SPROM8_TXRXC_SWITCH_SHIFT);
SPEX(opo, SSB_SPROM8_OFDM2GPO, 0x00ff, 0);
SPEX_ARRAY8(mcs2gpo, SSB_SPROM8_2G_MCSPO, ~0, 0);
SPEX_ARRAY8(mcs5gpo, SSB_SPROM8_5G_MCSPO, ~0, 0);
SPEX_ARRAY8(mcs5glpo, SSB_SPROM8_5GL_MCSPO, ~0, 0);
SPEX_ARRAY8(mcs5ghpo, SSB_SPROM8_5GH_MCSPO, ~0, 0);
SPEX(rawtempsense, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_RAWTEMP,
SSB_SPROM8_RAWTS_RAWTEMP_SHIFT);
SPEX(measpower, SSB_SPROM8_RAWTS, SSB_SPROM8_RAWTS_MEASPOWER,
SSB_SPROM8_RAWTS_MEASPOWER_SHIFT);
SPEX(tempsense_slope, SSB_SPROM8_OPT_CORRX,
SSB_SPROM8_OPT_CORRX_TEMP_SLOPE,
SSB_SPROM8_OPT_CORRX_TEMP_SLOPE_SHIFT);
SPEX(tempcorrx, SSB_SPROM8_OPT_CORRX, SSB_SPROM8_OPT_CORRX_TEMPCORRX,
SSB_SPROM8_OPT_CORRX_TEMPCORRX_SHIFT);
SPEX(tempsense_option, SSB_SPROM8_OPT_CORRX,
SSB_SPROM8_OPT_CORRX_TEMP_OPTION,
SSB_SPROM8_OPT_CORRX_TEMP_OPTION_SHIFT);
SPEX(freqoffset_corr, SSB_SPROM8_HWIQ_IQSWP,
SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR,
SSB_SPROM8_HWIQ_IQSWP_FREQ_CORR_SHIFT);
SPEX(iqcal_swp_dis, SSB_SPROM8_HWIQ_IQSWP,
SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP,
SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT);
SPEX(hw_iqcal_en, SSB_SPROM8_HWIQ_IQSWP, SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL,
SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT);
SPEX(bw40po, SSB_SPROM8_BW40PO, ~0, 0);
SPEX(cddpo, SSB_SPROM8_CDDPO, ~0, 0);
SPEX(stbcpo, SSB_SPROM8_STBCPO, ~0, 0);
SPEX(bwduppo, SSB_SPROM8_BWDUPPO, ~0, 0);
SPEX(tempthresh, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_TRESH,
SSB_SPROM8_THERMAL_TRESH_SHIFT);
SPEX(tempoffset, SSB_SPROM8_THERMAL, SSB_SPROM8_THERMAL_OFFSET,
SSB_SPROM8_THERMAL_OFFSET_SHIFT);
SPEX(phycal_tempdelta, SSB_SPROM8_TEMPDELTA,
SSB_SPROM8_TEMPDELTA_PHYCAL,
SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT);
SPEX(temps_period, SSB_SPROM8_TEMPDELTA, SSB_SPROM8_TEMPDELTA_PERIOD,
SSB_SPROM8_TEMPDELTA_PERIOD_SHIFT);
SPEX(temps_hysteresis, SSB_SPROM8_TEMPDELTA,
SSB_SPROM8_TEMPDELTA_HYSTERESIS,
SSB_SPROM8_TEMPDELTA_HYSTERESIS_SHIFT);
}
/*

View File

@ -81,6 +81,9 @@ static struct usb_device_id ath3k_table[] = {
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE02C) },
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C) },
{ } /* Terminating entry */
};
@ -99,6 +102,9 @@ static struct usb_device_id ath3k_blist_tbl[] = {
{ USB_DEVICE(0x13d3, 0x3362), .driver_info = BTUSB_ATH3012 },
{ USB_DEVICE(0x0cf3, 0xe004), .driver_info = BTUSB_ATH3012 },
/* Atheros AR5BBU22 with sflash firmware */
{ USB_DEVICE(0x0489, 0xE03C), .driver_info = BTUSB_ATH3012 },
{ } /* Terminating entry */
};

View File

@ -67,6 +67,7 @@ struct btmrvl_adapter {
u8 wakeup_tries;
wait_queue_head_t cmd_wait_q;
u8 cmd_complete;
bool is_suspended;
};
struct btmrvl_private {
@ -139,8 +140,10 @@ void btmrvl_check_evtpkt(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_process_event(struct btmrvl_private *priv, struct sk_buff *skb);
int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd);
int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv);
int btmrvl_enable_ps(struct btmrvl_private *priv);
int btmrvl_prepare_command(struct btmrvl_private *priv);
int btmrvl_enable_hs(struct btmrvl_private *priv);
#ifdef CONFIG_DEBUG_FS
void btmrvl_debugfs_init(struct hci_dev *hdev);

View File

@ -200,6 +200,36 @@ int btmrvl_send_module_cfg_cmd(struct btmrvl_private *priv, int subcmd)
}
EXPORT_SYMBOL_GPL(btmrvl_send_module_cfg_cmd);
int btmrvl_send_hscfg_cmd(struct btmrvl_private *priv)
{
struct sk_buff *skb;
struct btmrvl_cmd *cmd;
skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
if (!skb) {
BT_ERR("No free skb");
return -ENOMEM;
}
cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF,
BT_CMD_HOST_SLEEP_CONFIG));
cmd->length = 2;
cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);
bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
skb->dev = (void *) priv->btmrvl_dev.hcidev;
skb_queue_head(&priv->adapter->tx_queue, skb);
BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x", cmd->data[0],
cmd->data[1]);
return 0;
}
EXPORT_SYMBOL_GPL(btmrvl_send_hscfg_cmd);
int btmrvl_enable_ps(struct btmrvl_private *priv)
{
struct sk_buff *skb;
@ -232,7 +262,7 @@ int btmrvl_enable_ps(struct btmrvl_private *priv)
}
EXPORT_SYMBOL_GPL(btmrvl_enable_ps);
static int btmrvl_enable_hs(struct btmrvl_private *priv)
int btmrvl_enable_hs(struct btmrvl_private *priv)
{
struct sk_buff *skb;
struct btmrvl_cmd *cmd;
@ -268,35 +298,15 @@ static int btmrvl_enable_hs(struct btmrvl_private *priv)
return ret;
}
EXPORT_SYMBOL_GPL(btmrvl_enable_hs);
int btmrvl_prepare_command(struct btmrvl_private *priv)
{
struct sk_buff *skb = NULL;
struct btmrvl_cmd *cmd;
int ret = 0;
if (priv->btmrvl_dev.hscfgcmd) {
priv->btmrvl_dev.hscfgcmd = 0;
skb = bt_skb_alloc(sizeof(*cmd), GFP_ATOMIC);
if (skb == NULL) {
BT_ERR("No free skb");
return -ENOMEM;
}
cmd = (struct btmrvl_cmd *) skb_put(skb, sizeof(*cmd));
cmd->ocf_ogf = cpu_to_le16(hci_opcode_pack(OGF, BT_CMD_HOST_SLEEP_CONFIG));
cmd->length = 2;
cmd->data[0] = (priv->btmrvl_dev.gpio_gap & 0xff00) >> 8;
cmd->data[1] = (u8) (priv->btmrvl_dev.gpio_gap & 0x00ff);
bt_cb(skb)->pkt_type = MRVL_VENDOR_PKT;
skb->dev = (void *) priv->btmrvl_dev.hcidev;
skb_queue_head(&priv->adapter->tx_queue, skb);
BT_DBG("Queue HSCFG Command, gpio=0x%x, gap=0x%x",
cmd->data[0], cmd->data[1]);
btmrvl_send_hscfg_cmd(priv);
}
if (priv->btmrvl_dev.pscmd) {

View File

@ -339,9 +339,7 @@ static int btmrvl_sdio_download_helper(struct btmrvl_sdio_card *card)
done:
kfree(tmphlprbuf);
if (fw_helper)
release_firmware(fw_helper);
release_firmware(fw_helper);
return ret;
}
@ -484,10 +482,7 @@ static int btmrvl_sdio_download_fw_w_helper(struct btmrvl_sdio_card *card)
done:
kfree(tmpfwbuf);
if (fw_firmware)
release_firmware(fw_firmware);
release_firmware(fw_firmware);
return ret;
}
@ -1013,6 +1008,9 @@ static int btmrvl_sdio_probe(struct sdio_func *func,
priv->btmrvl_dev.psmode = 1;
btmrvl_enable_ps(priv);
priv->btmrvl_dev.gpio_gap = 0xffff;
btmrvl_send_hscfg_cmd(priv);
return 0;
disable_host_int:
@ -1048,11 +1046,111 @@ static void btmrvl_sdio_remove(struct sdio_func *func)
}
}
static int btmrvl_sdio_suspend(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct btmrvl_sdio_card *card;
struct btmrvl_private *priv;
mmc_pm_flag_t pm_flags;
struct hci_dev *hcidev;
if (func) {
pm_flags = sdio_get_host_pm_caps(func);
BT_DBG("%s: suspend: PM flags = 0x%x", sdio_func_id(func),
pm_flags);
if (!(pm_flags & MMC_PM_KEEP_POWER)) {
BT_ERR("%s: cannot remain alive while suspended",
sdio_func_id(func));
return -ENOSYS;
}
card = sdio_get_drvdata(func);
if (!card || !card->priv) {
BT_ERR("card or priv structure is not valid");
return 0;
}
} else {
BT_ERR("sdio_func is not specified");
return 0;
}
priv = card->priv;
if (priv->adapter->hs_state != HS_ACTIVATED) {
if (btmrvl_enable_hs(priv)) {
BT_ERR("HS not actived, suspend failed!");
return -EBUSY;
}
}
hcidev = priv->btmrvl_dev.hcidev;
BT_DBG("%s: SDIO suspend", hcidev->name);
hci_suspend_dev(hcidev);
skb_queue_purge(&priv->adapter->tx_queue);
priv->adapter->is_suspended = true;
/* We will keep the power when hs enabled successfully */
if (priv->adapter->hs_state == HS_ACTIVATED) {
BT_DBG("suspend with MMC_PM_KEEP_POWER");
return sdio_set_host_pm_flags(func, MMC_PM_KEEP_POWER);
} else {
BT_DBG("suspend without MMC_PM_KEEP_POWER");
return 0;
}
}
static int btmrvl_sdio_resume(struct device *dev)
{
struct sdio_func *func = dev_to_sdio_func(dev);
struct btmrvl_sdio_card *card;
struct btmrvl_private *priv;
mmc_pm_flag_t pm_flags;
struct hci_dev *hcidev;
if (func) {
pm_flags = sdio_get_host_pm_caps(func);
BT_DBG("%s: resume: PM flags = 0x%x", sdio_func_id(func),
pm_flags);
card = sdio_get_drvdata(func);
if (!card || !card->priv) {
BT_ERR("card or priv structure is not valid");
return 0;
}
} else {
BT_ERR("sdio_func is not specified");
return 0;
}
priv = card->priv;
if (!priv->adapter->is_suspended) {
BT_DBG("device already resumed");
return 0;
}
priv->adapter->is_suspended = false;
hcidev = priv->btmrvl_dev.hcidev;
BT_DBG("%s: SDIO resume", hcidev->name);
hci_resume_dev(hcidev);
priv->hw_wakeup_firmware(priv);
priv->adapter->hs_state = HS_DEACTIVATED;
BT_DBG("%s: HS DEACTIVATED in resume!", hcidev->name);
return 0;
}
static const struct dev_pm_ops btmrvl_sdio_pm_ops = {
.suspend = btmrvl_sdio_suspend,
.resume = btmrvl_sdio_resume,
};
static struct sdio_driver bt_mrvl_sdio = {
.name = "btmrvl_sdio",
.id_table = btmrvl_sdio_ids,
.probe = btmrvl_sdio_probe,
.remove = btmrvl_sdio_remove,
.drv = {
.owner = THIS_MODULE,
.pm = &btmrvl_sdio_pm_ops,
}
};
static int __init btmrvl_sdio_init_module(void)

View File

@ -143,6 +143,9 @@ static struct usb_device_id blacklist_table[] = {
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe02c), .driver_info = BTUSB_IGNORE },
/* Atheros AR5BBU12 with sflash firmware */
{ USB_DEVICE(0x0489, 0xe03c), .driver_info = BTUSB_ATH3012 },
/* Broadcom BCM2035 */
{ USB_DEVICE(0x0a5c, 0x2035), .driver_info = BTUSB_WRONG_SCO_MTU },
{ USB_DEVICE(0x0a5c, 0x200a), .driver_info = BTUSB_WRONG_SCO_MTU },
@ -855,6 +858,7 @@ static void btusb_work(struct work_struct *work)
{
struct btusb_data *data = container_of(work, struct btusb_data, work);
struct hci_dev *hdev = data->hdev;
int new_alts;
int err;
if (hdev->conn_hash.sco_num > 0) {
@ -868,11 +872,19 @@ static void btusb_work(struct work_struct *work)
set_bit(BTUSB_DID_ISO_RESUME, &data->flags);
}
if (data->isoc_altsetting != 2) {
if (hdev->voice_setting & 0x0020) {
static const int alts[3] = { 2, 4, 5 };
new_alts = alts[hdev->conn_hash.sco_num - 1];
} else {
new_alts = hdev->conn_hash.sco_num;
}
if (data->isoc_altsetting != new_alts) {
clear_bit(BTUSB_ISOC_RUNNING, &data->flags);
usb_kill_anchored_urbs(&data->isoc_anchor);
if (__set_isoc_interface(hdev, 2) < 0)
if (__set_isoc_interface(hdev, new_alts) < 0)
return;
}

View File

@ -388,7 +388,7 @@ static int hci_uart_register_dev(struct hci_uart *hu)
hdev->close = hci_uart_close;
hdev->flush = hci_uart_flush;
hdev->send = hci_uart_send_frame;
hdev->parent = hu->tty->dev;
SET_HCIDEV_DEV(hdev, hu->tty->dev);
if (test_bit(HCI_UART_RAW_DEVICE, &hu->hdev_flags))
set_bit(HCI_QUIRK_RAW_DEVICE, &hdev->quirks);

View File

@ -252,8 +252,9 @@ static int vhci_open(struct inode *inode, struct file *file)
}
file->private_data = data;
nonseekable_open(inode, file);
return nonseekable_open(inode, file);
return 0;
}
static int vhci_release(struct inode *inode, struct file *file)

View File

@ -693,8 +693,8 @@ ath6kl_add_bss_if_needed(struct ath6kl_vif *vif,
ie, 2 + vif->ssid_len + beacon_ie_len,
0, GFP_KERNEL);
if (bss)
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "added bss %pM to "
"cfg80211\n", bssid);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"added bss %pM to cfg80211\n", bssid);
kfree(ie);
} else
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "cfg80211 already has a bss\n");
@ -882,6 +882,32 @@ void ath6kl_cfg80211_disconnect_event(struct ath6kl_vif *vif, u8 reason,
vif->sme_state = SME_DISCONNECTED;
}
static int ath6kl_set_probed_ssids(struct ath6kl *ar,
struct ath6kl_vif *vif,
struct cfg80211_ssid *ssids, int n_ssids)
{
u8 i;
if (n_ssids > MAX_PROBED_SSID_INDEX)
return -EINVAL;
for (i = 0; i < n_ssids; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
ssids[i].ssid_len ?
SPECIFIC_SSID_FLAG : ANY_SSID_FLAG,
ssids[i].ssid_len,
ssids[i].ssid);
}
/* Make sure no old entries are left behind */
for (i = n_ssids; i < MAX_PROBED_SSID_INDEX; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx, i,
DISABLE_SSID_FLAG, 0, NULL);
}
return 0;
}
static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
struct cfg80211_scan_request *request)
{
@ -899,36 +925,25 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
if (!ar->usr_bss_filter) {
clear_bit(CLEAR_BSSFILTER_ON_BEACON, &vif->flags);
ret = ath6kl_wmi_bssfilter_cmd(
ar->wmi, vif->fw_vif_idx,
(test_bit(CONNECTED, &vif->flags) ?
ALL_BUT_BSS_FILTER : ALL_BSS_FILTER), 0);
ret = ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx,
ALL_BSS_FILTER, 0);
if (ret) {
ath6kl_err("couldn't set bss filtering\n");
return ret;
}
}
if (request->n_ssids && request->ssids[0].ssid_len) {
u8 i;
if (request->n_ssids > (MAX_PROBED_SSID_INDEX - 1))
request->n_ssids = MAX_PROBED_SSID_INDEX - 1;
for (i = 0; i < request->n_ssids; i++)
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
i + 1, SPECIFIC_SSID_FLAG,
request->ssids[i].ssid_len,
request->ssids[i].ssid);
}
ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
request->n_ssids);
if (ret < 0)
return ret;
/* this also clears IE in fw if it's not set */
ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
WMI_FRAME_PROBE_REQ,
request->ie, request->ie_len);
if (ret) {
ath6kl_err("failed to set Probe Request appie for "
"scan");
ath6kl_err("failed to set Probe Request appie for scan");
return ret;
}
@ -945,8 +960,7 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy, struct net_device *ndev,
channels = kzalloc(n_channels * sizeof(u16), GFP_KERNEL);
if (channels == NULL) {
ath6kl_warn("failed to set scan channels, "
"scan all channels");
ath6kl_warn("failed to set scan channels, scan all channels");
n_channels = 0;
}
@ -1018,6 +1032,20 @@ out:
vif->scan_req = NULL;
}
void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
enum wmi_phy_mode mode)
{
enum nl80211_channel_type type;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"channel switch notify nw_type %d freq %d mode %d\n",
vif->nw_type, freq, mode);
type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;
cfg80211_ch_switch_notify(vif->ndev, freq, type);
}
static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
u8 key_index, bool pairwise,
const u8 *mac_addr,
@ -1111,9 +1139,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
ar->ap_mode_bkey.key_len = key->key_len;
memcpy(ar->ap_mode_bkey.key, key->key, key->key_len);
if (!test_bit(CONNECTED, &vif->flags)) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay initial group "
"key configuration until AP mode has been "
"started\n");
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"Delay initial group key configuration until AP mode has been started\n");
/*
* The key will be set in ath6kl_connect_ap_mode() once
* the connected event is received from the target.
@ -1129,8 +1156,8 @@ static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
* the AP mode has properly started
* (ath6kl_install_statioc_wep_keys).
*/
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delay WEP key configuration "
"until AP mode has been started\n");
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"Delay WEP key configuration until AP mode has been started\n");
vif->wep_key_list[key_index].key_len = key->key_len;
memcpy(vif->wep_key_list[key_index].key, key->key,
key->key_len);
@ -1962,8 +1989,7 @@ static int ath6kl_wow_sta(struct ath6kl *ar, struct ath6kl_vif *vif)
sizeof(discvr_pattern), discvr_offset,
discvr_pattern, discvr_mask);
if (ret) {
ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR "
"pattern\n");
ath6kl_err("failed to add WOW mDNS/SSDP/LLMNR pattern\n");
return ret;
}
}
@ -2031,6 +2057,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
u8 index = 0;
__be32 ips[MAX_IP_ADDRS];
/* The FW currently can't support multi-vif WoW properly. */
if (ar->num_vif > 1)
return -EIO;
vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
@ -2044,6 +2074,13 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
return -EINVAL;
if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags)) {
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
vif->fw_vif_idx, false);
if (ret)
return ret;
}
/* Clear existing WOW patterns */
for (i = 0; i < WOW_MAX_FILTERS_PER_LIST; i++)
ath6kl_wmi_del_wow_pattern_cmd(ar->wmi, vif->fw_vif_idx,
@ -2147,8 +2184,8 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_HOST_MODE_AWAKE);
if (ret) {
ath6kl_warn("Failed to configure host sleep mode for "
"wow resume: %d\n", ret);
ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
ret);
ar->state = ATH6KL_STATE_WOW;
return ret;
}
@ -2172,6 +2209,13 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
ar->state = ATH6KL_STATE_ON;
if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags)) {
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
vif->fw_vif_idx, true);
if (ret)
return ret;
}
netif_wake_queue(vif->ndev);
return 0;
@ -2186,8 +2230,10 @@ static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
if (!vif)
return -EIO;
if (!ath6kl_cfg80211_ready(vif))
if (!test_bit(WMI_READY, &ar->flag)) {
ath6kl_err("deepsleep failed as wmi is not ready\n");
return -EIO;
}
ath6kl_cfg80211_stop_all(ar);
@ -2447,6 +2493,24 @@ static int ath6kl_set_htcap(struct ath6kl_vif *vif, enum ieee80211_band band,
band, htcap);
}
static int ath6kl_restore_htcap(struct ath6kl_vif *vif)
{
struct wiphy *wiphy = vif->ar->wiphy;
int band, ret = 0;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
if (!wiphy->bands[band])
continue;
ret = ath6kl_set_htcap(vif, band,
wiphy->bands[band]->ht_cap.ht_supported);
if (ret)
return ret;
}
return ret;
}
static bool ath6kl_is_p2p_ie(const u8 *pos)
{
return pos[0] == WLAN_EID_VENDOR_SPECIFIC && pos[1] >= 4 &&
@ -2568,28 +2632,34 @@ static int ath6kl_get_rsn_capab(struct cfg80211_beacon_data *beacon,
/* skip element id and length */
rsn_ie += 2;
/* skip version, group cipher */
if (rsn_ie_len < 6)
/* skip version */
if (rsn_ie_len < 2)
return -EINVAL;
rsn_ie += 6;
rsn_ie_len -= 6;
rsn_ie += 2;
rsn_ie_len -= 2;
/* skip group cipher suite */
if (rsn_ie_len < 4)
return 0;
rsn_ie += 4;
rsn_ie_len -= 4;
/* skip pairwise cipher suite */
if (rsn_ie_len < 2)
return -EINVAL;
cnt = *((u16 *) rsn_ie);
return 0;
cnt = get_unaligned_le16(rsn_ie);
rsn_ie += (2 + cnt * 4);
rsn_ie_len -= (2 + cnt * 4);
/* skip akm suite */
if (rsn_ie_len < 2)
return -EINVAL;
cnt = *((u16 *) rsn_ie);
return 0;
cnt = get_unaligned_le16(rsn_ie);
rsn_ie += (2 + cnt * 4);
rsn_ie_len -= (2 + cnt * 4);
if (rsn_ie_len < 2)
return -EINVAL;
return 0;
memcpy(rsn_capab, rsn_ie, 2);
@ -2766,6 +2836,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
return res;
}
memcpy(&vif->profile, &p, sizeof(p));
res = ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx, &p);
if (res < 0)
return res;
@ -2801,13 +2872,7 @@ static int ath6kl_stop_ap(struct wiphy *wiphy, struct net_device *dev)
clear_bit(CONNECTED, &vif->flags);
/* Restore ht setting in firmware */
if (ath6kl_set_htcap(vif, IEEE80211_BAND_2GHZ, true))
return -EIO;
if (ath6kl_set_htcap(vif, IEEE80211_BAND_5GHZ, true))
return -EIO;
return 0;
return ath6kl_restore_htcap(vif);
}
static const u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@ -3081,7 +3146,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
struct ath6kl_vif *vif = netdev_priv(dev);
u16 interval;
int ret;
u8 i;
if (ar->state != ATH6KL_STATE_ON)
return -EIO;
@ -3089,29 +3153,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
if (vif->sme_state != SME_DISCONNECTED)
return -EBUSY;
/* The FW currently can't support multi-vif WoW properly. */
if (ar->num_vif > 1)
return -EIO;
ath6kl_cfg80211_scan_complete_event(vif, true);
for (i = 0; i < ar->wiphy->max_sched_scan_ssids; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
i, DISABLE_SSID_FLAG,
0, NULL);
}
ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
request->n_ssids);
if (ret < 0)
return ret;
/* fw uses seconds, also make sure that it's >0 */
interval = max_t(u16, 1, request->interval / 1000);
ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
interval, interval,
10, 0, 0, 0, 3, 0, 0, 0);
if (request->n_ssids && request->ssids[0].ssid_len) {
for (i = 0; i < request->n_ssids; i++) {
ath6kl_wmi_probedssid_cmd(ar->wmi, vif->fw_vif_idx,
i, SPECIFIC_SSID_FLAG,
request->ssids[i].ssid_len,
request->ssids[i].ssid);
}
}
vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
ATH6KL_WOW_MODE_ENABLE,
@ -3271,8 +3329,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
if (ath6kl_wmi_powermode_cmd(ar->wmi, 0, REC_POWER) != 0)
ath6kl_warn("ath6kl_deep_sleep_enable: "
"wmi_powermode_cmd failed\n");
ath6kl_warn("ath6kl_deep_sleep_enable: wmi_powermode_cmd failed\n");
return;
}
@ -3352,6 +3409,7 @@ struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
vif->next_mode = nw_type;
vif->listen_intvl_t = ATH6KL_DEFAULT_LISTEN_INTVAL;
vif->bmiss_time_t = ATH6KL_DEFAULT_BMISS_TIME;
vif->bg_scan_period = 0;
vif->htcap.ht_enable = true;
memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
@ -3393,6 +3451,7 @@ err:
int ath6kl_cfg80211_init(struct ath6kl *ar)
{
struct wiphy *wiphy = ar->wiphy;
bool band_2gig = false, band_5gig = false, ht = false;
int ret;
wiphy->mgmt_stypes = ath6kl_mgmt_stypes;
@ -3413,8 +3472,46 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
/* max num of ssids that can be probed during scanning */
wiphy->max_scan_ssids = MAX_PROBED_SSID_INDEX;
wiphy->max_scan_ie_len = 1000; /* FIX: what is correct limit? */
wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
switch (ar->hw.cap) {
case WMI_11AN_CAP:
ht = true;
case WMI_11A_CAP:
band_5gig = true;
break;
case WMI_11GN_CAP:
ht = true;
case WMI_11G_CAP:
band_2gig = true;
break;
case WMI_11AGN_CAP:
ht = true;
case WMI_11AG_CAP:
band_2gig = true;
band_5gig = true;
break;
default:
ath6kl_err("invalid phy capability!\n");
return -EINVAL;
}
/*
* Even if the fw has HT support, advertise HT cap only when
* the firmware has support to override RSN capability, otherwise
* 4-way handshake would fail.
*/
if (!(ht &&
test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
ar->fw_capabilities))) {
ath6kl_band_2ghz.ht_cap.cap = 0;
ath6kl_band_2ghz.ht_cap.ht_supported = false;
ath6kl_band_5ghz.ht_cap.cap = 0;
ath6kl_band_5ghz.ht_cap.ht_supported = false;
}
if (band_2gig)
wiphy->bands[IEEE80211_BAND_2GHZ] = &ath6kl_band_2ghz;
if (band_5gig)
wiphy->bands[IEEE80211_BAND_5GHZ] = &ath6kl_band_5ghz;
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->cipher_suites = cipher_suites;
@ -3430,7 +3527,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
wiphy->wowlan.pattern_min_len = 1;
wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
wiphy->max_sched_scan_ssids = 10;
wiphy->max_sched_scan_ssids = MAX_PROBED_SSID_INDEX;
ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
WIPHY_FLAG_HAVE_AP_SME |
@ -3447,8 +3544,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
ar->wiphy->probe_resp_offload =
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P;
ret = wiphy_register(wiphy);
if (ret < 0) {

View File

@ -28,6 +28,8 @@ enum ath6kl_cfg_suspend_mode {
struct net_device *ath6kl_interface_add(struct ath6kl *ar, char *name,
enum nl80211_iftype type,
u8 fw_vif_idx, u8 nw_type);
void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
enum wmi_phy_mode mode);
void ath6kl_cfg80211_scan_complete_event(struct ath6kl_vif *vif, bool aborted);
void ath6kl_cfg80211_connect_event(struct ath6kl_vif *vif, u16 channel,

View File

@ -126,9 +126,9 @@ struct ath6kl_fw_ie {
#define AR6003_HW_2_0_FIRMWARE_FILE "athwlan.bin.z77"
#define AR6003_HW_2_0_TCMD_FIRMWARE_FILE "athtcmd_ram.bin"
#define AR6003_HW_2_0_PATCH_FILE "data.patch.bin"
#define AR6003_HW_2_0_BOARD_DATA_FILE "ath6k/AR6003/hw2.0/bdata.bin"
#define AR6003_HW_2_0_BOARD_DATA_FILE AR6003_HW_2_0_FW_DIR "/bdata.bin"
#define AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6003/hw2.0/bdata.SD31.bin"
AR6003_HW_2_0_FW_DIR "/bdata.SD31.bin"
/* AR6003 3.0 definitions */
#define AR6003_HW_2_1_1_VERSION 0x30000582
@ -139,25 +139,33 @@ struct ath6kl_fw_ie {
#define AR6003_HW_2_1_1_UTF_FIRMWARE_FILE "utf.bin"
#define AR6003_HW_2_1_1_TESTSCRIPT_FILE "nullTestFlow.bin"
#define AR6003_HW_2_1_1_PATCH_FILE "data.patch.bin"
#define AR6003_HW_2_1_1_BOARD_DATA_FILE "ath6k/AR6003/hw2.1.1/bdata.bin"
#define AR6003_HW_2_1_1_BOARD_DATA_FILE AR6003_HW_2_1_1_FW_DIR "/bdata.bin"
#define AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6003/hw2.1.1/bdata.SD31.bin"
AR6003_HW_2_1_1_FW_DIR "/bdata.SD31.bin"
/* AR6004 1.0 definitions */
#define AR6004_HW_1_0_VERSION 0x30000623
#define AR6004_HW_1_0_FW_DIR "ath6k/AR6004/hw1.0"
#define AR6004_HW_1_0_FIRMWARE_FILE "fw.ram.bin"
#define AR6004_HW_1_0_BOARD_DATA_FILE "ath6k/AR6004/hw1.0/bdata.bin"
#define AR6004_HW_1_0_BOARD_DATA_FILE AR6004_HW_1_0_FW_DIR "/bdata.bin"
#define AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6004/hw1.0/bdata.DB132.bin"
AR6004_HW_1_0_FW_DIR "/bdata.DB132.bin"
/* AR6004 1.1 definitions */
#define AR6004_HW_1_1_VERSION 0x30000001
#define AR6004_HW_1_1_FW_DIR "ath6k/AR6004/hw1.1"
#define AR6004_HW_1_1_FIRMWARE_FILE "fw.ram.bin"
#define AR6004_HW_1_1_BOARD_DATA_FILE "ath6k/AR6004/hw1.1/bdata.bin"
#define AR6004_HW_1_1_BOARD_DATA_FILE AR6004_HW_1_1_FW_DIR "/bdata.bin"
#define AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE \
"ath6k/AR6004/hw1.1/bdata.DB132.bin"
AR6004_HW_1_1_FW_DIR "/bdata.DB132.bin"
/* AR6004 1.2 definitions */
#define AR6004_HW_1_2_VERSION 0x300007e8
#define AR6004_HW_1_2_FW_DIR "ath6k/AR6004/hw1.2"
#define AR6004_HW_1_2_FIRMWARE_FILE "fw.ram.bin"
#define AR6004_HW_1_2_BOARD_DATA_FILE AR6004_HW_1_2_FW_DIR "/bdata.bin"
#define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \
AR6004_HW_1_2_FW_DIR "/bdata.bin"
/* Per STA data, used in AP mode */
#define STA_PS_AWAKE BIT(0)
@ -502,6 +510,8 @@ enum ath6kl_vif_state {
WLAN_ENABLED,
STATS_UPDATE_PEND,
HOST_SLEEP_MODE_CMD_PROCESSED,
NETDEV_MCAST_ALL_ON,
NETDEV_MCAST_ALL_OFF,
};
struct ath6kl_vif {
@ -549,9 +559,11 @@ struct ath6kl_vif {
u16 assoc_bss_beacon_int;
u16 listen_intvl_t;
u16 bmiss_time_t;
u16 bg_scan_period;
u8 assoc_bss_dtim_period;
struct net_device_stats net_stats;
struct target_stats target_stats;
struct wmi_connect_cmd profile;
struct list_head mc_filter;
};
@ -640,6 +652,7 @@ struct ath6kl {
u8 sta_list_index;
struct ath6kl_req_key ap_mode_bkey;
struct sk_buff_head mcastpsq;
u32 want_ch_switch;
/*
* FIXME: protects access to mcastpsq but is actually useless as
@ -672,6 +685,7 @@ struct ath6kl {
u32 refclk_hz;
u32 uarttx_pin;
u32 testscript_addr;
enum wmi_phy_cap cap;
struct ath6kl_hw_fw {
const char *dir;
@ -805,7 +819,8 @@ void aggr_reset_state(struct aggr_info_conn *aggr_conn);
struct ath6kl_sta *ath6kl_find_sta(struct ath6kl_vif *vif, u8 *node_addr);
struct ath6kl_sta *ath6kl_find_sta_by_aid(struct ath6kl *ar, u8 aid);
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver);
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
enum wmi_phy_cap cap);
int ath6kl_control_tx(void *devt, struct sk_buff *skb,
enum htc_endpoint_id eid);
void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel,

View File

@ -401,8 +401,10 @@ static ssize_t ath6kl_fwlog_block_read(struct file *file,
ret = wait_for_completion_interruptible(
&ar->debug.fwlog_completion);
if (ret == -ERESTARTSYS)
if (ret == -ERESTARTSYS) {
vfree(buf);
return ret;
}
spin_lock(&ar->debug.fwlog_queue.lock);
}
@ -1570,10 +1572,15 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file,
size_t count, loff_t *ppos)
{
struct ath6kl *ar = file->private_data;
struct ath6kl_vif *vif;
u16 bgscan_int;
char buf[32];
ssize_t len;
vif = ath6kl_vif_first(ar);
if (!vif)
return -EIO;
len = min(count, sizeof(buf) - 1);
if (copy_from_user(buf, user_buf, len))
return -EFAULT;
@ -1585,6 +1592,8 @@ static ssize_t ath6kl_bgscan_int_write(struct file *file,
if (bgscan_int == 0)
bgscan_int = 0xffff;
vif->bg_scan_period = bgscan_int;
ath6kl_wmi_scanparams_cmd(ar->wmi, 0, 0, 0, bgscan_int, 0, 0, 0, 3,
0, 0, 0);
@ -1809,6 +1818,7 @@ int ath6kl_debug_init_fs(struct ath6kl *ar)
void ath6kl_debug_cleanup(struct ath6kl *ar)
{
skb_queue_purge(&ar->debug.fwlog_queue);
complete(&ar->debug.fwlog_completion);
kfree(ar->debug.roam_tbl);
}

View File

@ -83,10 +83,7 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
* never goes inactive EVER.
*/
cur_ep_dist->dist_flags |= HTC_EP_ACTIVE;
} else if (cur_ep_dist->svc_id == WMI_DATA_BK_SVC)
/* this is the lowest priority data endpoint */
/* FIXME: this looks fishy, check */
cred_info->lowestpri_ep_dist = cur_ep_dist->list;
}
/*
* Streams have to be created (explicit | implicit) for all
@ -100,6 +97,13 @@ static void ath6kl_credit_init(struct ath6kl_htc_credit_info *cred_info,
*/
}
/*
* For ath6kl_credit_seek function,
* it use list_for_each_entry_reverse to walk around the whole ep list.
* Therefore assign this lowestpri_ep_dist after walk around the ep_list
*/
cred_info->lowestpri_ep_dist = cur_ep_dist->list;
WARN_ON(cred_info->cur_free_credits <= 0);
list_for_each_entry(cur_ep_dist, ep_list, list) {
@ -758,7 +762,7 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
u32 txb_mask;
u8 ac = WMM_NUM_AC;
if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) ||
if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) &&
(WMI_CONTROL_SVC != endpoint->svc_id))
ac = target->dev->ar->ep2ac_map[endpoint->eid];
@ -793,16 +797,17 @@ static void ath6kl_htc_tx_bundle(struct htc_endpoint *endpoint,
* itself
*/
txb_mask = ((1 << ac) - 1);
/*
* when the scatter request resources drop below a
* certain threshold, disable Tx bundling for all
* AC's with priority lower than the current requesting
* AC. Otherwise re-enable Tx bundling for them
*/
if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS)
target->tx_bndl_mask &= ~txb_mask;
else
target->tx_bndl_mask |= txb_mask;
/*
* when the scatter request resources drop below a
* certain threshold, disable Tx bundling for all
* AC's with priority lower than the current requesting
* AC. Otherwise re-enable Tx bundling for them
*/
if (scat_req->scat_q_depth < ATH6KL_SCATTER_REQS)
target->tx_bndl_mask &= ~txb_mask;
else
target->tx_bndl_mask |= txb_mask;
}
ath6kl_dbg(ATH6KL_DBG_HTC, "htc tx pkts to scatter: %d\n",
@ -849,6 +854,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
int bundle_sent;
int n_pkts_bundle;
u8 ac = WMM_NUM_AC;
int status;
spin_lock_bh(&target->tx_lock);
@ -866,7 +872,7 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
*/
INIT_LIST_HEAD(&txq);
if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) ||
if ((HTC_CTRL_RSVD_SVC != endpoint->svc_id) &&
(WMI_CONTROL_SVC != endpoint->svc_id))
ac = target->dev->ar->ep2ac_map[endpoint->eid];
@ -910,7 +916,12 @@ static void ath6kl_htc_tx_from_queue(struct htc_target *target,
ath6kl_htc_tx_prep_pkt(packet, packet->info.tx.flags,
0, packet->info.tx.seqno);
ath6kl_htc_tx_issue(target, packet);
status = ath6kl_htc_tx_issue(target, packet);
if (status) {
packet->status = status;
packet->completion(packet->context, packet);
}
}
spin_lock_bh(&target->tx_lock);

View File

@ -108,8 +108,6 @@ static void get_htc_packet_credit_based(struct htc_target *target,
/* get packet at head, but don't remove it */
packet = list_first_entry(&ep->txq, struct htc_packet, list);
if (packet == NULL)
break;
ath6kl_dbg(ATH6KL_DBG_HTC,
"%s: got head packet:0x%p , queue depth: %d\n",
@ -803,8 +801,6 @@ static int htc_send_packets_multiple(struct htc_target *target,
/* get first packet to find out which ep the packets will go into */
packet = list_first_entry(pkt_queue, struct htc_packet, list);
if (packet == NULL)
return -EINVAL;
if (packet->endpoint >= ENDPOINT_MAX) {
WARN_ON_ONCE(1);
@ -1382,6 +1378,9 @@ static int ath6kl_htc_pipe_conn_service(struct htc_target *target,
/* copy all the callbacks */
ep->ep_cb = conn_req->ep_cb;
/* initialize tx_drop_packet_threshold */
ep->tx_drop_packet_threshold = MAX_HI_COOKIE_NUM;
status = ath6kl_hif_pipe_map_service(ar, ep->svc_id,
&ep->pipe.pipeid_ul,
&ep->pipe.pipeid_dl);
@ -1636,10 +1635,6 @@ static int ath6kl_htc_pipe_add_rxbuf_multiple(struct htc_target *target,
return -EINVAL;
first = list_first_entry(pkt_queue, struct htc_packet, list);
if (first == NULL) {
WARN_ON_ONCE(1);
return -EINVAL;
}
if (first->endpoint >= ENDPOINT_MAX) {
WARN_ON_ONCE(1);

View File

@ -119,6 +119,24 @@ static const struct ath6kl_hw hw_list[] = {
.fw_board = AR6004_HW_1_1_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,
},
{
.id = AR6004_HW_1_2_VERSION,
.name = "ar6004 hw 1.2",
.dataset_patch_addr = 0x436ecc,
.app_load_addr = 0x1234,
.board_ext_data_addr = 0x437000,
.reserved_ram_size = 9216,
.board_addr = 0x435c00,
.refclk_hz = 40000000,
.uarttx_pin = 11,
.fw = {
.dir = AR6004_HW_1_2_FW_DIR,
.fw = AR6004_HW_1_2_FIRMWARE_FILE,
},
.fw_board = AR6004_HW_1_2_BOARD_DATA_FILE,
.fw_default_board = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE,
},
};
/*
@ -445,9 +463,9 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
P2P_FLAG_MACADDR_REQ |
P2P_FLAG_HMODEL_REQ);
if (ret) {
ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P "
"capabilities (%d) - assuming P2P not "
"supported\n", ret);
ath6kl_dbg(ATH6KL_DBG_TRC,
"failed to request P2P capabilities (%d) - assuming P2P not supported\n",
ret);
ar->p2p = false;
}
}
@ -456,8 +474,9 @@ static int ath6kl_target_config_wlan_params(struct ath6kl *ar, int idx)
/* Enable Probe Request reporting for P2P */
ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true);
if (ret) {
ath6kl_dbg(ATH6KL_DBG_TRC, "failed to enable Probe "
"Request reporting (%d)\n", ret);
ath6kl_dbg(ATH6KL_DBG_TRC,
"failed to enable Probe Request reporting (%d)\n",
ret);
}
}

View File

@ -421,8 +421,8 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
if (!ik->valid)
break;
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed addkey for "
"the initial group key for AP mode\n");
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"Delayed addkey for the initial group key for AP mode\n");
memset(key_rsc, 0, sizeof(key_rsc));
res = ath6kl_wmi_addkey_cmd(
ar->wmi, vif->fw_vif_idx, ik->key_index, ik->key_type,
@ -430,12 +430,19 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
ik->key,
KEY_OP_INIT_VAL, NULL, SYNC_BOTH_WMIFLAG);
if (res) {
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "Delayed "
"addkey failed: %d\n", res);
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
"Delayed addkey failed: %d\n", res);
}
break;
}
if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) {
ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
/* we actually don't know the phymode, default to HT20 */
ath6kl_cfg80211_ch_switch_notify(vif, channel,
WMI_11G_HT20);
}
ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);
set_bit(CONNECTED, &vif->flags);
netif_carrier_on(vif->ndev);
@ -541,7 +548,8 @@ void ath6kl_disconnect(struct ath6kl_vif *vif)
/* WMI Event handlers */
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver,
enum wmi_phy_cap cap)
{
struct ath6kl *ar = devt;
@ -551,6 +559,7 @@ void ath6kl_ready_event(void *devt, u8 *datap, u32 sw_ver, u32 abi_ver)
ar->version.wlan_ver = sw_ver;
ar->version.abi_ver = abi_ver;
ar->hw.cap = cap;
snprintf(ar->wiphy->fw_version,
sizeof(ar->wiphy->fw_version),
@ -584,6 +593,45 @@ void ath6kl_scan_complete_evt(struct ath6kl_vif *vif, int status)
ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "scan complete: %d\n", status);
}
static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
{
struct ath6kl *ar = vif->ar;
vif->next_chan = channel;
vif->profile.ch = cpu_to_le16(channel);
switch (vif->nw_type) {
case AP_NETWORK:
return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,
&vif->profile);
default:
ath6kl_err("won't switch channels nw_type=%d\n", vif->nw_type);
return -ENOTSUPP;
}
}
static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
{
struct ath6kl_vif *vif;
int res = 0;
if (!ar->want_ch_switch)
return;
spin_lock_bh(&ar->list_lock);
list_for_each_entry(vif, &ar->vif_list, list) {
if (ar->want_ch_switch & (1 << vif->fw_vif_idx))
res = ath6kl_commit_ch_switch(vif, channel);
if (res)
ath6kl_err("channel switch failed nw_type %d res %d\n",
vif->nw_type, res);
}
spin_unlock_bh(&ar->list_lock);
}
void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
u16 listen_int, u16 beacon_int,
enum network_type net_type, u8 beacon_ie_len,
@ -601,9 +649,11 @@ void ath6kl_connect_event(struct ath6kl_vif *vif, u16 channel, u8 *bssid,
memcpy(vif->bssid, bssid, sizeof(vif->bssid));
vif->bss_ch = channel;
if ((vif->nw_type == INFRA_NETWORK))
if ((vif->nw_type == INFRA_NETWORK)) {
ath6kl_wmi_listeninterval_cmd(ar->wmi, vif->fw_vif_idx,
vif->listen_intvl_t, 0);
ath6kl_check_ch_switch(ar, channel);
}
netif_wake_queue(vif->ndev);
@ -926,6 +976,11 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
struct ath6kl *ar = vif->ar;
if (vif->nw_type == AP_NETWORK) {
/* disconnect due to other STA vif switching channels */
if (reason == BSS_DISCONNECTED &&
prot_reason_status == WMI_AP_REASON_STA_ROAM)
ar->want_ch_switch |= 1 << vif->fw_vif_idx;
if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
return;
@ -1090,7 +1145,7 @@ static int ath6kl_set_features(struct net_device *dev,
static void ath6kl_set_multicast_list(struct net_device *ndev)
{
struct ath6kl_vif *vif = netdev_priv(ndev);
bool mc_all_on = false, mc_all_off = false;
bool mc_all_on = false;
int mc_count = netdev_mc_count(ndev);
struct netdev_hw_addr *ha;
bool found;
@ -1102,24 +1157,41 @@ static void ath6kl_set_multicast_list(struct net_device *ndev)
!test_bit(WLAN_ENABLED, &vif->flags))
return;
/* Enable multicast-all filter. */
mc_all_on = !!(ndev->flags & IFF_PROMISC) ||
!!(ndev->flags & IFF_ALLMULTI) ||
!!(mc_count > ATH6K_MAX_MC_FILTERS_PER_LIST);
mc_all_off = !(ndev->flags & IFF_MULTICAST) || mc_count == 0;
if (mc_all_on)
set_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
else
clear_bit(NETDEV_MCAST_ALL_ON, &vif->flags);
if (mc_all_on || mc_all_off) {
/* Enable/disable all multicast */
ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast filter\n",
mc_all_on ? "enabling" : "disabling");
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
mc_all_on = mc_all_on || (vif->ar->state == ATH6KL_STATE_ON);
if (!(ndev->flags & IFF_MULTICAST)) {
mc_all_on = false;
set_bit(NETDEV_MCAST_ALL_OFF, &vif->flags);
} else {
clear_bit(NETDEV_MCAST_ALL_OFF, &vif->flags);
}
/* Enable/disable "multicast-all" filter*/
ath6kl_dbg(ATH6KL_DBG_TRC, "%s multicast-all filter\n",
mc_all_on ? "enabling" : "disabling");
ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi, vif->fw_vif_idx,
mc_all_on);
if (ret)
ath6kl_warn("Failed to %s multicast receive\n",
mc_all_on ? "enable" : "disable");
if (ret) {
ath6kl_warn("Failed to %s multicast-all receive\n",
mc_all_on ? "enable" : "disable");
return;
}
if (test_bit(NETDEV_MCAST_ALL_ON, &vif->flags))
return;
/* Keep the driver and firmware mcast list in sync. */
list_for_each_entry_safe(mc_filter, tmp, &vif->mc_filter, list) {
found = false;
netdev_for_each_mc_addr(ha, ndev) {

View File

@ -552,7 +552,7 @@ static int ath6kl_sdio_write_async(struct ath6kl *ar, u32 address, u8 *buffer,
bus_req = ath6kl_sdio_alloc_busreq(ar_sdio);
if (!bus_req)
if (WARN_ON_ONCE(!bus_req))
return -ENOMEM;
bus_req->address = address;
@ -915,6 +915,9 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
}
cut_pwr:
if (func->card && func->card->host)
func->card->host->pm_flags &= ~MMC_PM_KEEP_POWER;
return ath6kl_cfg80211_suspend(ar, ATH6KL_CFG_SUSPEND_CUTPOWER, NULL);
}
@ -985,9 +988,8 @@ static int ath6kl_set_addrwin_reg(struct ath6kl *ar, u32 reg_addr, u32 addr)
}
if (status) {
ath6kl_err("%s: failed to write initial bytes of 0x%x "
"to window reg: 0x%X\n", __func__,
addr, reg_addr);
ath6kl_err("%s: failed to write initial bytes of 0x%x to window reg: 0x%X\n",
__func__, addr, reg_addr);
return status;
}
@ -1076,8 +1078,8 @@ static int ath6kl_sdio_bmi_credits(struct ath6kl *ar)
(u8 *)&ar->bmi.cmd_credits, 4,
HIF_RD_SYNC_BYTE_INC);
if (ret) {
ath6kl_err("Unable to decrement the command credit "
"count register: %d\n", ret);
ath6kl_err("Unable to decrement the command credit count register: %d\n",
ret);
return ret;
}
@ -1457,3 +1459,6 @@ MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_FW_DIR "/" AR6004_HW_1_1_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);

View File

@ -362,15 +362,11 @@ int ath6kl_data_tx(struct sk_buff *skb, struct net_device *dev)
skb, skb->data, skb->len);
/* If target is not associated */
if (!test_bit(CONNECTED, &vif->flags)) {
dev_kfree_skb(skb);
return 0;
}
if (!test_bit(CONNECTED, &vif->flags))
goto fail_tx;
if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON)) {
dev_kfree_skb(skb);
return 0;
}
if (WARN_ON_ONCE(ar->state != ATH6KL_STATE_ON))
goto fail_tx;
if (!test_bit(WMI_READY, &ar->flag))
goto fail_tx;

View File

@ -1037,6 +1037,14 @@ static void ath6kl_usb_stop(struct ath6kl *ar)
hif_stop(ar);
}
static void ath6kl_usb_cleanup_scatter(struct ath6kl *ar)
{
/*
* USB doesn't support it. Just return.
*/
return;
}
static const struct ath6kl_hif_ops ath6kl_usb_ops = {
.diag_read32 = ath6kl_usb_diag_read32,
.diag_write32 = ath6kl_usb_diag_write32,
@ -1049,6 +1057,7 @@ static const struct ath6kl_hif_ops ath6kl_usb_ops = {
.pipe_get_default = ath6kl_usb_get_default_pipe,
.pipe_map_service = ath6kl_usb_map_service_pipe,
.pipe_get_free_queue_number = ath6kl_usb_get_free_queue_number,
.cleanup_scatter = ath6kl_usb_cleanup_scatter,
};
/* ath6kl usb driver registered functions */
@ -1207,3 +1216,6 @@ MODULE_FIRMWARE(AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);

View File

@ -16,6 +16,7 @@
*/
#include <linux/ip.h>
#include <linux/in.h>
#include "core.h"
#include "debug.h"
#include "testmode.h"
@ -289,6 +290,13 @@ int ath6kl_wmi_implicit_create_pstream(struct wmi *wmi, u8 if_idx,
layer2_priority);
} else
usr_pri = layer2_priority & 0x7;
/*
* Queue the EAPOL frames in the same WMM_AC_VO queue
* as that of management frames.
*/
if (skb->protocol == cpu_to_be16(ETH_P_PAE))
usr_pri = WMI_VOICE_USER_PRIORITY;
}
/*
@ -460,8 +468,9 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
freq, dur);
chan = ieee80211_get_channel(ar->wiphy, freq);
if (!chan) {
ath6kl_dbg(ATH6KL_DBG_WMI, "remain_on_chnl: Unknown channel "
"(freq=%u)\n", freq);
ath6kl_dbg(ATH6KL_DBG_WMI,
"remain_on_chnl: Unknown channel (freq=%u)\n",
freq);
return -EINVAL;
}
id = vif->last_roc_id;
@ -488,12 +497,14 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
ev = (struct wmi_cancel_remain_on_chnl_event *) datap;
freq = le32_to_cpu(ev->freq);
dur = le32_to_cpu(ev->duration);
ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: freq=%u dur=%u "
"status=%u\n", freq, dur, ev->status);
ath6kl_dbg(ATH6KL_DBG_WMI,
"cancel_remain_on_chnl: freq=%u dur=%u status=%u\n",
freq, dur, ev->status);
chan = ieee80211_get_channel(ar->wiphy, freq);
if (!chan) {
ath6kl_dbg(ATH6KL_DBG_WMI, "cancel_remain_on_chnl: Unknown "
"channel (freq=%u)\n", freq);
ath6kl_dbg(ATH6KL_DBG_WMI,
"cancel_remain_on_chnl: Unknown channel (freq=%u)\n",
freq);
return -EINVAL;
}
if (vif->last_cancel_roc_id &&
@ -548,12 +559,12 @@ static int ath6kl_wmi_rx_probe_req_event_rx(struct wmi *wmi, u8 *datap, int len,
freq = le32_to_cpu(ev->freq);
dlen = le16_to_cpu(ev->len);
if (datap + len < ev->data + dlen) {
ath6kl_err("invalid wmi_p2p_rx_probe_req_event: "
"len=%d dlen=%u\n", len, dlen);
ath6kl_err("invalid wmi_p2p_rx_probe_req_event: len=%d dlen=%u\n",
len, dlen);
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "rx_probe_req: len=%u freq=%u "
"probe_req_report=%d\n",
ath6kl_dbg(ATH6KL_DBG_WMI,
"rx_probe_req: len=%u freq=%u probe_req_report=%d\n",
dlen, freq, vif->probe_req_report);
if (vif->probe_req_report || vif->nw_type == AP_NETWORK)
@ -592,8 +603,8 @@ static int ath6kl_wmi_rx_action_event_rx(struct wmi *wmi, u8 *datap, int len,
freq = le32_to_cpu(ev->freq);
dlen = le16_to_cpu(ev->len);
if (datap + len < ev->data + dlen) {
ath6kl_err("invalid wmi_rx_action_event: "
"len=%d dlen=%u\n", len, dlen);
ath6kl_err("invalid wmi_rx_action_event: len=%d dlen=%u\n",
len, dlen);
return -EINVAL;
}
ath6kl_dbg(ATH6KL_DBG_WMI, "rx_action: len=%u freq=%u\n", dlen, freq);
@ -687,7 +698,7 @@ static int ath6kl_wmi_ready_event_rx(struct wmi *wmi, u8 *datap, int len)
ath6kl_ready_event(wmi->parent_dev, ev->mac_addr,
le32_to_cpu(ev->sw_version),
le32_to_cpu(ev->abi_version));
le32_to_cpu(ev->abi_version), ev->phy_cap);
return 0;
}
@ -777,16 +788,15 @@ static int ath6kl_wmi_connect_event_rx(struct wmi *wmi, u8 *datap, int len,
/* AP mode start/STA connected event */
struct net_device *dev = vif->ndev;
if (memcmp(dev->dev_addr, ev->u.ap_bss.bssid, ETH_ALEN) == 0) {
ath6kl_dbg(ATH6KL_DBG_WMI, "%s: freq %d bssid %pM "
"(AP started)\n",
ath6kl_dbg(ATH6KL_DBG_WMI,
"%s: freq %d bssid %pM (AP started)\n",
__func__, le16_to_cpu(ev->u.ap_bss.ch),
ev->u.ap_bss.bssid);
ath6kl_connect_ap_mode_bss(
vif, le16_to_cpu(ev->u.ap_bss.ch));
} else {
ath6kl_dbg(ATH6KL_DBG_WMI, "%s: aid %u mac_addr %pM "
"auth=%u keymgmt=%u cipher=%u apsd_info=%u "
"(STA connected)\n",
ath6kl_dbg(ATH6KL_DBG_WMI,
"%s: aid %u mac_addr %pM auth=%u keymgmt=%u cipher=%u apsd_info=%u (STA connected)\n",
__func__, ev->u.ap_sta.aid,
ev->u.ap_sta.mac_addr,
ev->u.ap_sta.auth,
@ -1229,8 +1239,9 @@ static int ath6kl_wmi_neighbor_report_event_rx(struct wmi *wmi, u8 *datap,
ev = (struct wmi_neighbor_report_event *) datap;
if (sizeof(*ev) + ev->num_neighbors * sizeof(struct wmi_neighbor_info)
> len) {
ath6kl_dbg(ATH6KL_DBG_WMI, "truncated neighbor event "
"(num=%d len=%d)\n", ev->num_neighbors, len);
ath6kl_dbg(ATH6KL_DBG_WMI,
"truncated neighbor event (num=%d len=%d)\n",
ev->num_neighbors, len);
return -EINVAL;
}
for (i = 0; i < ev->num_neighbors; i++) {
@ -1814,12 +1825,14 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
u32 home_dwell_time, u32 force_scan_interval,
s8 num_chan, u16 *ch_list, u32 no_cck, u32 *rates)
{
struct ieee80211_supported_band *sband;
struct sk_buff *skb;
struct wmi_begin_scan_cmd *sc;
s8 size;
s8 size, *supp_rates;
int i, band, ret;
struct ath6kl *ar = wmi->parent_dev;
int num_rates;
u32 ratemask;
size = sizeof(struct wmi_begin_scan_cmd);
@ -1846,10 +1859,13 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
sc->num_ch = num_chan;
for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
struct ieee80211_supported_band *sband =
ar->wiphy->bands[band];
u32 ratemask = rates[band];
u8 *supp_rates = sc->supp_rates[band].rates;
sband = ar->wiphy->bands[band];
if (!sband)
continue;
ratemask = rates[band];
supp_rates = sc->supp_rates[band].rates;
num_rates = 0;
for (i = 0; i < sband->n_bitrates; i++) {
@ -2129,8 +2145,8 @@ int ath6kl_wmi_addkey_cmd(struct wmi *wmi, u8 if_idx, u8 key_index,
struct wmi_add_cipher_key_cmd *cmd;
int ret;
ath6kl_dbg(ATH6KL_DBG_WMI, "addkey cmd: key_index=%u key_type=%d "
"key_usage=%d key_len=%d key_op_ctrl=%d\n",
ath6kl_dbg(ATH6KL_DBG_WMI,
"addkey cmd: key_index=%u key_type=%d key_usage=%d key_len=%d key_op_ctrl=%d\n",
key_index, key_type, key_usage, key_len, key_op_ctrl);
if ((key_index > WMI_MAX_KEY_INDEX) || (key_len > WMI_MAX_KEY_LEN) ||
@ -3047,8 +3063,8 @@ int ath6kl_wmi_ap_profile_commit(struct wmi *wmip, u8 if_idx,
res = ath6kl_wmi_cmd_send(wmip, if_idx, skb, WMI_AP_CONFIG_COMMIT_CMDID,
NO_SYNC_WMIFLAG);
ath6kl_dbg(ATH6KL_DBG_WMI, "%s: nw_type=%u auth_mode=%u ch=%u "
"ctrl_flags=0x%x-> res=%d\n",
ath6kl_dbg(ATH6KL_DBG_WMI,
"%s: nw_type=%u auth_mode=%u ch=%u ctrl_flags=0x%x-> res=%d\n",
__func__, p->nw_type, p->auth_mode, le16_to_cpu(p->ch),
le32_to_cpu(p->ctrl_flags), res);
return res;
@ -3208,8 +3224,9 @@ int ath6kl_wmi_set_appie_cmd(struct wmi *wmi, u8 if_idx, u8 mgmt_frm_type,
if (!skb)
return -ENOMEM;
ath6kl_dbg(ATH6KL_DBG_WMI, "set_appie_cmd: mgmt_frm_type=%u "
"ie_len=%u\n", mgmt_frm_type, ie_len);
ath6kl_dbg(ATH6KL_DBG_WMI,
"set_appie_cmd: mgmt_frm_type=%u ie_len=%u\n",
mgmt_frm_type, ie_len);
p = (struct wmi_set_appie_cmd *) skb->data;
p->mgmt_frm_type = mgmt_frm_type;
p->ie_len = ie_len;
@ -3310,8 +3327,9 @@ static int ath6kl_wmi_send_action_cmd(struct wmi *wmi, u8 if_idx, u32 id,
wmi->last_mgmt_tx_frame = buf;
wmi->last_mgmt_tx_frame_len = data_len;
ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
"len=%u\n", id, freq, wait, data_len);
ath6kl_dbg(ATH6KL_DBG_WMI,
"send_action_cmd: id=%u freq=%u wait=%u len=%u\n",
id, freq, wait, data_len);
p = (struct wmi_send_action_cmd *) skb->data;
p->id = cpu_to_le32(id);
p->freq = cpu_to_le32(freq);
@ -3348,8 +3366,9 @@ static int __ath6kl_wmi_send_mgmt_cmd(struct wmi *wmi, u8 if_idx, u32 id,
wmi->last_mgmt_tx_frame = buf;
wmi->last_mgmt_tx_frame_len = data_len;
ath6kl_dbg(ATH6KL_DBG_WMI, "send_action_cmd: id=%u freq=%u wait=%u "
"len=%u\n", id, freq, wait, data_len);
ath6kl_dbg(ATH6KL_DBG_WMI,
"send_action_cmd: id=%u freq=%u wait=%u len=%u\n",
id, freq, wait, data_len);
p = (struct wmi_send_mgmt_cmd *) skb->data;
p->id = cpu_to_le32(id);
p->freq = cpu_to_le32(freq);
@ -3402,8 +3421,9 @@ int ath6kl_wmi_send_probe_response_cmd(struct wmi *wmi, u8 if_idx, u32 freq,
if (!skb)
return -ENOMEM;
ath6kl_dbg(ATH6KL_DBG_WMI, "send_probe_response_cmd: freq=%u dst=%pM "
"len=%u\n", freq, dst, data_len);
ath6kl_dbg(ATH6KL_DBG_WMI,
"send_probe_response_cmd: freq=%u dst=%pM len=%u\n",
freq, dst, data_len);
p = (struct wmi_p2p_probe_response_cmd *) skb->data;
p->freq = cpu_to_le32(freq);
memcpy(p->destination_addr, dst, ETH_ALEN);

View File

@ -106,6 +106,8 @@ struct wmi_data_sync_bufs {
#define WMM_AC_VI 2 /* video */
#define WMM_AC_VO 3 /* voice */
#define WMI_VOICE_USER_PRIORITY 0x7
struct wmi {
u16 stream_exist_for_ac[WMM_NUM_AC];
u8 fat_pipe_exist;
@ -1151,6 +1153,7 @@ enum wmi_phy_mode {
WMI_11AG_MODE = 0x3,
WMI_11B_MODE = 0x4,
WMI_11GONLY_MODE = 0x5,
WMI_11G_HT20 = 0x6,
};
#define WMI_MAX_CHANNELS 32
@ -1416,6 +1419,16 @@ struct wmi_ready_event_2 {
u8 phy_cap;
} __packed;
/* WMI_PHY_CAPABILITY */
enum wmi_phy_cap {
WMI_11A_CAP = 0x01,
WMI_11G_CAP = 0x02,
WMI_11AG_CAP = 0x03,
WMI_11AN_CAP = 0x04,
WMI_11GN_CAP = 0x05,
WMI_11AGN_CAP = 0x06,
};
/* Connect Event */
struct wmi_connect_event {
union {
@ -1468,6 +1481,17 @@ enum wmi_disconnect_reason {
IBSS_MERGE = 0xe,
};
/* AP mode disconnect proto_reasons */
enum ap_disconnect_reason {
WMI_AP_REASON_STA_LEFT = 101,
WMI_AP_REASON_FROM_HOST = 102,
WMI_AP_REASON_COMM_TIMEOUT = 103,
WMI_AP_REASON_MAX_STA = 104,
WMI_AP_REASON_ACL = 105,
WMI_AP_REASON_STA_ROAM = 106,
WMI_AP_REASON_DFS_CHANNEL = 107,
};
#define ATH6KL_COUNTRY_RD_SHIFT 16
struct ath6kl_wmi_regdomain {

View File

@ -892,34 +892,6 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
}
static bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
{
struct ath9k_rtt_hist *hist;
u32 *table;
int i;
bool restore;
if (!ah->caldata)
return false;
hist = &ah->caldata->rtt_hist;
if (!hist->num_readings)
return false;
ar9003_hw_rtt_enable(ah);
ar9003_hw_rtt_set_mask(ah, 0x00);
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->rxchainmask & (1 << i)))
continue;
table = &hist->table[i][hist->num_readings][0];
ar9003_hw_rtt_load_hist(ah, i, table);
}
restore = ar9003_hw_rtt_force_restore(ah);
ar9003_hw_rtt_disable(ah);
return restore;
}
static bool ar9003_hw_init_cal(struct ath_hw *ah,
struct ath9k_channel *chan)
{
@ -942,9 +914,10 @@ static bool ar9003_hw_init_cal(struct ath_hw *ah,
if (!ar9003_hw_rtt_restore(ah, chan))
run_rtt_cal = true;
ath_dbg(common, CALIBRATE, "RTT restore %s\n",
run_rtt_cal ? "failed" : "succeed");
if (run_rtt_cal)
ath_dbg(common, CALIBRATE, "RTT calibration to be done\n");
}
run_agc_cal = run_rtt_cal;
if (run_rtt_cal) {
@ -1069,17 +1042,14 @@ skip_tx_iqcal:
#undef CL_TAB_ENTRY
if (run_rtt_cal && caldata) {
struct ath9k_rtt_hist *hist = &caldata->rtt_hist;
if (is_reusable && (hist->num_readings < RTT_HIST_MAX)) {
u32 *table;
if (is_reusable) {
if (!ath9k_hw_rfbus_req(ah))
ath_err(ath9k_hw_common(ah),
"Could not stop baseband\n");
else
ar9003_hw_rtt_fill_hist(ah);
hist->num_readings++;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->rxchainmask & (1 << i)))
continue;
table = &hist->table[i][hist->num_readings][0];
ar9003_hw_rtt_fill_hist(ah, i, table);
}
ath9k_hw_rfbus_done(ah);
}
ar9003_hw_rtt_disable(ah);

View File

@ -756,7 +756,7 @@ int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (caldata) {
caldata->done_txiqcal_once = false;
caldata->done_txclcal_once = false;
caldata->rtt_hist.num_readings = 0;
caldata->rtt_done = false;
}
if (!ath9k_hw_init_cal(ah, chan))

View File

@ -15,6 +15,7 @@
*/
#include "hw.h"
#include "hw-ops.h"
#include "ar9003_phy.h"
#include "ar9003_rtt.h"
@ -69,7 +70,7 @@ bool ar9003_hw_rtt_force_restore(struct ath_hw *ah)
}
static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain,
u32 index, u32 data28)
u32 index, u32 data28)
{
u32 val;
@ -100,12 +101,21 @@ static void ar9003_hw_rtt_load_hist_entry(struct ath_hw *ah, u8 chain,
RTT_ACCESS_TIMEOUT);
}
void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table)
void ar9003_hw_rtt_load_hist(struct ath_hw *ah)
{
int i;
int chain, i;
for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
ar9003_hw_rtt_load_hist_entry(ah, chain, i, table[i]);
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
if (!(ah->rxchainmask & (1 << chain)))
continue;
for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
ar9003_hw_rtt_load_hist_entry(ah, chain, i,
ah->caldata->rtt_table[chain][i]);
ath_dbg(ath9k_hw_common(ah), CALIBRATE,
"Load RTT value at idx %d, chain %d: 0x%x\n",
i, chain, ah->caldata->rtt_table[chain][i]);
}
}
}
static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
@ -128,27 +138,71 @@ static int ar9003_hw_rtt_fill_hist_entry(struct ath_hw *ah, u8 chain, u32 index)
RTT_ACCESS_TIMEOUT))
return RTT_BAD_VALUE;
val = REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain));
val = MS(REG_READ(ah, AR_PHY_RTT_TABLE_SW_INTF_1_B(chain)),
AR_PHY_RTT_SW_RTT_TABLE_DATA);
return val;
}
void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table)
void ar9003_hw_rtt_fill_hist(struct ath_hw *ah)
{
int i;
int chain, i;
for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
table[i] = ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
if (!(ah->rxchainmask & (1 << chain)))
continue;
for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++) {
ah->caldata->rtt_table[chain][i] =
ar9003_hw_rtt_fill_hist_entry(ah, chain, i);
ath_dbg(ath9k_hw_common(ah), CALIBRATE,
"RTT value at idx %d, chain %d is: 0x%x\n",
i, chain, ah->caldata->rtt_table[chain][i]);
}
}
ah->caldata->rtt_done = true;
}
void ar9003_hw_rtt_clear_hist(struct ath_hw *ah)
{
int i, j;
int chain, i;
for (i = 0; i < AR9300_MAX_CHAINS; i++) {
if (!(ah->rxchainmask & (1 << i)))
for (chain = 0; chain < AR9300_MAX_CHAINS; chain++) {
if (!(ah->rxchainmask & (1 << chain)))
continue;
for (j = 0; j < MAX_RTT_TABLE_ENTRY; j++)
ar9003_hw_rtt_load_hist_entry(ah, i, j, 0);
for (i = 0; i < MAX_RTT_TABLE_ENTRY; i++)
ar9003_hw_rtt_load_hist_entry(ah, chain, i, 0);
}
if (ah->caldata)
ah->caldata->rtt_done = false;
}
bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan)
{
bool restore;
if (!ah->caldata)
return false;
if (!ah->caldata->rtt_done)
return false;
ar9003_hw_rtt_enable(ah);
ar9003_hw_rtt_set_mask(ah, 0x10);
if (!ath9k_hw_rfbus_req(ah)) {
ath_err(ath9k_hw_common(ah), "Could not stop baseband\n");
restore = false;
goto fail;
}
ar9003_hw_rtt_load_hist(ah);
restore = ar9003_hw_rtt_force_restore(ah);
fail:
ath9k_hw_rfbus_done(ah);
ar9003_hw_rtt_disable(ah);
return restore;
}

View File

@ -21,8 +21,9 @@ void ar9003_hw_rtt_enable(struct ath_hw *ah);
void ar9003_hw_rtt_disable(struct ath_hw *ah);
void ar9003_hw_rtt_set_mask(struct ath_hw *ah, u32 rtt_mask);
bool ar9003_hw_rtt_force_restore(struct ath_hw *ah);
void ar9003_hw_rtt_load_hist(struct ath_hw *ah, u8 chain, u32 *table);
void ar9003_hw_rtt_fill_hist(struct ath_hw *ah, u8 chain, u32 *table);
void ar9003_hw_rtt_load_hist(struct ath_hw *ah);
void ar9003_hw_rtt_fill_hist(struct ath_hw *ah);
void ar9003_hw_rtt_clear_hist(struct ath_hw *ah);
bool ar9003_hw_rtt_restore(struct ath_hw *ah, struct ath9k_channel *chan);
#endif

View File

@ -1702,10 +1702,10 @@ static int ath9k_hw_do_fastcc(struct ath_hw *ah, struct ath9k_channel *chan)
* For AR9462, make sure that calibration data for
* re-using are present.
*/
if (AR_SREV_9462(ah) && (!ah->caldata ||
!ah->caldata->done_txiqcal_once ||
!ah->caldata->done_txclcal_once ||
!ah->caldata->rtt_hist.num_readings))
if (AR_SREV_9462(ah) && (ah->caldata &&
(!ah->caldata->done_txiqcal_once ||
!ah->caldata->done_txclcal_once ||
!ah->caldata->rtt_done)))
goto fail;
ath_dbg(common, RESET, "FastChannelChange for %d -> %d\n",
@ -1941,7 +1941,6 @@ int ath9k_hw_reset(struct ath_hw *ah, struct ath9k_channel *chan,
if (caldata) {
caldata->done_txiqcal_once = false;
caldata->done_txclcal_once = false;
caldata->rtt_hist.num_readings = 0;
}
if (!ath9k_hw_init_cal(ah, chan))
return -EIO;

View File

@ -348,12 +348,6 @@ enum ath9k_int {
CHANNEL_HT40MINUS)
#define MAX_RTT_TABLE_ENTRY 6
#define RTT_HIST_MAX 3
struct ath9k_rtt_hist {
u32 table[AR9300_MAX_CHAINS][RTT_HIST_MAX][MAX_RTT_TABLE_ENTRY];
u8 num_readings;
};
#define MAX_IQCAL_MEASUREMENT 8
#define MAX_CL_TAB_ENTRY 16
@ -363,6 +357,7 @@ struct ath9k_hw_cal_data {
int32_t CalValid;
int8_t iCoff;
int8_t qCoff;
bool rtt_done;
bool paprd_done;
bool nfcal_pending;
bool nfcal_interference;
@ -373,8 +368,8 @@ struct ath9k_hw_cal_data {
u32 num_measures[AR9300_MAX_CHAINS];
int tx_corr_coeff[MAX_IQCAL_MEASUREMENT][AR9300_MAX_CHAINS];
u32 tx_clcal[AR9300_MAX_CHAINS][MAX_CL_TAB_ENTRY];
u32 rtt_table[AR9300_MAX_CHAINS][MAX_RTT_TABLE_ENTRY];
struct ath9k_nfcal_hist nfCalHist[NUM_NF_READINGS];
struct ath9k_rtt_hist rtt_hist;
};
struct ath9k_channel {

View File

@ -107,11 +107,9 @@ struct b43_bus_dev *b43_bus_dev_bcma_init(struct bcma_device *core)
dev->dma_dev = core->dma_dev;
dev->irq = core->irq;
/*
dev->board_vendor = core->bus->boardinfo.vendor;
dev->board_type = core->bus->boardinfo.type;
dev->board_rev = core->bus->boardinfo.rev;
*/
dev->board_rev = core->bus->sprom.board_rev;
dev->chip_id = core->bus->chipinfo.id;
dev->chip_rev = core->bus->chipinfo.rev;
@ -210,7 +208,7 @@ struct b43_bus_dev *b43_bus_dev_ssb_init(struct ssb_device *sdev)
dev->board_vendor = sdev->bus->boardinfo.vendor;
dev->board_type = sdev->bus->boardinfo.type;
dev->board_rev = sdev->bus->boardinfo.rev;
dev->board_rev = sdev->bus->sprom.board_rev;
dev->chip_id = sdev->bus->chip_id;
dev->chip_rev = sdev->bus->chip_rev;

View File

@ -1109,7 +1109,7 @@ static bool b43_dma_translation_in_low_word(struct b43_wldev *dev,
#ifdef CONFIG_B43_SSB
if (dev->dev->bus_type == B43_BUS_SSB &&
dev->dev->sdev->bus->bustype == SSB_BUSTYPE_PCI &&
!(dev->dev->sdev->bus->host_pci->is_pcie &&
!(pci_is_pcie(dev->dev->sdev->bus->host_pci) &&
ssb_read32(dev->dev->sdev, SSB_TMSHIGH) & SSB_TMSHIGH_DMA64))
return 1;
#endif

View File

@ -5243,10 +5243,10 @@ static void b43_sprom_fixup(struct ssb_bus *bus)
/* boardflags workarounds */
if (bus->boardinfo.vendor == SSB_BOARDVENDOR_DELL &&
bus->chip_id == 0x4301 && bus->boardinfo.rev == 0x74)
bus->chip_id == 0x4301 && bus->sprom.board_rev == 0x74)
bus->sprom.boardflags_lo |= B43_BFL_BTCOEXIST;
if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
bus->boardinfo.type == 0x4E && bus->boardinfo.rev > 0x40)
bus->boardinfo.type == 0x4E && bus->sprom.board_rev > 0x40)
bus->sprom.boardflags_lo |= B43_BFL_PACTRL;
if (bus->bustype == SSB_BUSTYPE_PCI) {
pdev = bus->host_pci;

View File

@ -1573,8 +1573,6 @@ static void b43legacy_request_firmware(struct work_struct *work)
const char *filename;
int err;
/* do dummy read */
ssb_read32(dev->dev, SSB_TMSHIGH);
if (!fw->ucode) {
if (rev == 2)
filename = "ucode2";
@ -3781,7 +3779,7 @@ static void b43legacy_sprom_fixup(struct ssb_bus *bus)
/* boardflags workarounds */
if (bus->boardinfo.vendor == PCI_VENDOR_ID_APPLE &&
bus->boardinfo.type == 0x4E &&
bus->boardinfo.rev > 0x40)
bus->sprom.board_rev > 0x40)
bus->sprom.boardflags_lo |= B43legacy_BFL_PACTRL;
}

View File

@ -408,7 +408,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
if (is_bcm_board_vendor(dev) &&
(dev->dev->bus->boardinfo.type == 0x0416) &&
(dev->dev->bus->boardinfo.rev == 0x0017))
(dev->dev->bus->sprom.board_rev == 0x0017))
return;
b43legacy_ilt_write(dev, 0x5001, 0x0002);
@ -424,7 +424,7 @@ static void b43legacy_phy_setupg(struct b43legacy_wldev *dev)
if (is_bcm_board_vendor(dev) &&
(dev->dev->bus->boardinfo.type == 0x0416) &&
(dev->dev->bus->boardinfo.rev == 0x0017))
(dev->dev->bus->sprom.board_rev == 0x0017))
return;
b43legacy_ilt_write(dev, 0x0401, 0x0002);

View File

@ -1998,7 +1998,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
if (phy->type == B43legacy_PHYTYPE_G) {
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421 &&
dev->dev->bus->boardinfo.rev >= 30)
dev->dev->bus->sprom.board_rev >= 30)
att = 3;
else if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x416)
@ -2008,7 +2008,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
} else {
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421 &&
dev->dev->bus->boardinfo.rev >= 30)
dev->dev->bus->sprom.board_rev >= 30)
att = 7;
else
att = 6;
@ -2018,7 +2018,7 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
if (phy->type == B43legacy_PHYTYPE_G) {
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421 &&
dev->dev->bus->boardinfo.rev >= 30)
dev->dev->bus->sprom.board_rev >= 30)
att = 3;
else if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type ==
@ -2052,9 +2052,9 @@ u16 b43legacy_default_radio_attenuation(struct b43legacy_wldev *dev)
}
if (is_bcm_board_vendor(dev) &&
dev->dev->bus->boardinfo.type == 0x421) {
if (dev->dev->bus->boardinfo.rev < 0x43)
if (dev->dev->bus->sprom.board_rev < 0x43)
att = 2;
else if (dev->dev->bus->boardinfo.rev < 0x51)
else if (dev->dev->bus->sprom.board_rev < 0x51)
att = 3;
}
if (att == 0xFFFF)

View File

@ -85,18 +85,15 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
sdiodev->irq_wake = true;
/* must configure SDIO_CCCR_IENx to enable irq */
data = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_0,
SDIO_CCCR_IENx, &ret);
data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx,
data, &ret);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, data, &ret);
/* redirect, configure ane enable io for interrupt signal */
data = SDIO_SEPINT_MASK | SDIO_SEPINT_OE;
if (sdiodev->irq_flags | IRQF_TRIGGER_HIGH)
data |= SDIO_SEPINT_ACT_HI;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT,
data, &ret);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
return 0;
}
@ -105,9 +102,8 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
{
brcmf_dbg(TRACE, "Entering\n");
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_BRCM_SEPINT,
0, NULL);
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_0, SDIO_CCCR_IENx, 0, NULL);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
if (sdiodev->irq_wake) {
disable_irq_wake(sdiodev->irq);
@ -158,153 +154,147 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
}
#endif /* CONFIG_BRCMFMAC_SDIO_OOB */
u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
int *err)
{
int status;
s32 retry = 0;
u8 data = 0;
do {
if (retry) /* wait for 1 ms till bus get settled down */
udelay(1000);
status = brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, fnc_num,
addr, (u8 *) &data);
} while (status != 0
&& (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
if (err)
*err = status;
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
fnc_num, addr, data);
return data;
}
void
brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint fnc_num, u32 addr,
u8 data, int *err)
{
int status;
s32 retry = 0;
do {
if (retry) /* wait for 1 ms till bus get settled down */
udelay(1000);
status = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, fnc_num,
addr, (u8 *) &data);
} while (status != 0
&& (retry++ < SDIOH_API_ACCESS_RETRY_LIMIT));
if (err)
*err = status;
brcmf_dbg(INFO, "fun = %d, addr = 0x%x, u8data = 0x%x\n",
fnc_num, addr, data);
}
int
brcmf_sdcard_set_sbaddr_window(struct brcmf_sdio_dev *sdiodev, u32 address)
{
int err = 0;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW,
(address >> 8) & SBSDIO_SBADDRLOW_MASK, &err);
if (!err)
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_SBADDRMID,
(address >> 16) & SBSDIO_SBADDRMID_MASK,
&err);
if (!err)
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_SBADDRHIGH,
(address >> 24) & SBSDIO_SBADDRHIGH_MASK,
&err);
int err = 0, i;
u8 addr[3];
s32 retry;
addr[0] = (address >> 8) & SBSDIO_SBADDRLOW_MASK;
addr[1] = (address >> 16) & SBSDIO_SBADDRMID_MASK;
addr[2] = (address >> 24) & SBSDIO_SBADDRHIGH_MASK;
for (i = 0; i < 3; i++) {
retry = 0;
do {
if (retry)
usleep_range(1000, 2000);
err = brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE,
SDIO_FUNC_1, SBSDIO_FUNC1_SBADDRLOW + i,
&addr[i]);
} while (err != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
if (err) {
brcmf_dbg(ERROR, "failed at addr:0x%0x\n",
SBSDIO_FUNC1_SBADDRLOW + i);
break;
}
}
return err;
}
u32 brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size)
static int
brcmf_sdio_regrw_helper(struct brcmf_sdio_dev *sdiodev, u32 addr,
void *data, bool write)
{
int status;
u32 word = 0;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
u8 func_num, reg_size;
u32 bar;
s32 retry = 0;
int ret;
brcmf_dbg(INFO, "fun = 1, addr = 0x%x\n", addr);
if (bar0 != sdiodev->sbwad) {
if (brcmf_sdcard_set_sbaddr_window(sdiodev, bar0))
return 0xFFFFFFFF;
sdiodev->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status = brcmf_sdioh_request_word(sdiodev, SDIOH_READ, SDIO_FUNC_1,
addr, &word, size);
sdiodev->regfail = (status != 0);
brcmf_dbg(INFO, "u32data = 0x%x\n", word);
/* if ok, return appropriately masked word */
if (status == 0) {
switch (size) {
case sizeof(u8):
return word & 0xff;
case sizeof(u16):
return word & 0xffff;
case sizeof(u32):
return word;
default:
sdiodev->regfail = true;
/*
* figure out how to read the register based on address range
* 0x00 ~ 0x7FF: function 0 CCCR and FBR
* 0x10000 ~ 0x1FFFF: function 1 miscellaneous registers
* The rest: function 1 silicon backplane core registers
*/
if ((addr & ~REG_F0_REG_MASK) == 0) {
func_num = SDIO_FUNC_0;
reg_size = 1;
} else if ((addr & ~REG_F1_MISC_MASK) == 0) {
func_num = SDIO_FUNC_1;
reg_size = 1;
} else {
func_num = SDIO_FUNC_1;
reg_size = 4;
/* Set the window for SB core register */
bar = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
if (bar != sdiodev->sbwad) {
ret = brcmf_sdcard_set_sbaddr_window(sdiodev, bar);
if (ret != 0) {
memset(data, 0xFF, reg_size);
return ret;
}
sdiodev->sbwad = bar;
}
}
/* otherwise, bad sdio access or invalid size */
brcmf_dbg(ERROR, "error reading addr 0x%04x size %d\n", addr, size);
return 0xFFFFFFFF;
}
u32 brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
u32 data)
{
int status;
uint bar0 = addr & ~SBSDIO_SB_OFT_ADDR_MASK;
int err = 0;
brcmf_dbg(INFO, "fun = 1, addr = 0x%x, uint%ddata = 0x%x\n",
addr, size * 8, data);
if (bar0 != sdiodev->sbwad) {
err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
if (err)
return err;
sdiodev->sbwad = bar0;
}
addr &= SBSDIO_SB_OFT_ADDR_MASK;
if (size == 4)
addr &= SBSDIO_SB_OFT_ADDR_MASK;
addr |= SBSDIO_SB_ACCESS_2_4B_FLAG;
status =
brcmf_sdioh_request_word(sdiodev, SDIOH_WRITE, SDIO_FUNC_1,
addr, &data, size);
sdiodev->regfail = (status != 0);
}
if (status == 0)
return 0;
do {
if (!write)
memset(data, 0, reg_size);
if (retry) /* wait for 1 ms till bus get settled down */
usleep_range(1000, 2000);
if (reg_size == 1)
ret = brcmf_sdioh_request_byte(sdiodev, write,
func_num, addr, data);
else
ret = brcmf_sdioh_request_word(sdiodev, write,
func_num, addr, data, 4);
} while (ret != 0 && retry++ < SDIOH_API_ACCESS_RETRY_LIMIT);
brcmf_dbg(ERROR, "error writing 0x%08x to addr 0x%04x size %d\n",
data, addr, size);
return 0xFFFFFFFF;
if (ret != 0)
brcmf_dbg(ERROR, "failed with %d\n", ret);
return ret;
}
bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev)
u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
{
return sdiodev->regfail;
u8 data;
int retval;
brcmf_dbg(INFO, "addr:0x%08x\n", addr);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
brcmf_dbg(INFO, "data:0x%02x\n", data);
if (ret)
*ret = retval;
return data;
}
u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
{
u32 data;
int retval;
brcmf_dbg(INFO, "addr:0x%08x\n", addr);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
brcmf_dbg(INFO, "data:0x%08x\n", data);
if (ret)
*ret = retval;
return data;
}
void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
u8 data, int *ret)
{
int retval;
brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
if (ret)
*ret = retval;
}
void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
u32 data, int *ret)
{
int retval;
brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
if (ret)
*ret = retval;
}
static int brcmf_sdcard_recv_prepare(struct brcmf_sdio_dev *sdiodev, uint fn,

View File

@ -346,43 +346,17 @@ int brcmf_sdioh_request_buffer(struct brcmf_sdio_dev *sdiodev,
return status;
}
/* Read client card reg */
static int
brcmf_sdioh_card_regread(struct brcmf_sdio_dev *sdiodev, int func, u32 regaddr,
int regsize, u32 *data)
{
if ((func == 0) || (regsize == 1)) {
u8 temp = 0;
brcmf_sdioh_request_byte(sdiodev, SDIOH_READ, func, regaddr,
&temp);
*data = temp;
*data &= 0xff;
brcmf_dbg(DATA, "byte read data=0x%02x\n", *data);
} else {
brcmf_sdioh_request_word(sdiodev, SDIOH_READ, func, regaddr,
data, regsize);
if (regsize == 2)
*data &= 0xffff;
brcmf_dbg(DATA, "word read data=0x%08x\n", *data);
}
return SUCCESS;
}
static int brcmf_sdioh_get_cisaddr(struct brcmf_sdio_dev *sdiodev, u32 regaddr)
{
/* read 24 bits and return valid 17 bit addr */
int i;
int i, ret;
u32 scratch, regdata;
__le32 scratch_le;
u8 *ptr = (u8 *)&scratch_le;
for (i = 0; i < 3; i++) {
if ((brcmf_sdioh_card_regread(sdiodev, 0, regaddr, 1,
&regdata)) != SUCCESS)
regdata = brcmf_sdio_regrl(sdiodev, regaddr, &ret);
if (ret != 0)
brcmf_dbg(ERROR, "Can't read!\n");
*ptr++ = (u8) regdata;

View File

@ -629,43 +629,29 @@ static bool data_ok(struct brcmf_sdio *bus)
* Reads a register in the SDIO hardware block. This block occupies a series of
* adresses on the 32 bit backplane bus.
*/
static void
r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 reg_offset, u32 *retryvar)
static int
r_sdreg32(struct brcmf_sdio *bus, u32 *regvar, u32 offset)
{
u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
*retryvar = 0;
do {
*regvar = brcmf_sdcard_reg_read(bus->sdiodev,
bus->ci->c_inf[idx].base + reg_offset,
sizeof(u32));
} while (brcmf_sdcard_regfail(bus->sdiodev) &&
(++(*retryvar) <= retry_limit));
if (*retryvar) {
bus->regfails += (*retryvar-1);
if (*retryvar > retry_limit) {
brcmf_dbg(ERROR, "FAILED READ %Xh\n", reg_offset);
*regvar = 0;
}
}
int ret;
*regvar = brcmf_sdio_regrl(bus->sdiodev,
bus->ci->c_inf[idx].base + offset, &ret);
return ret;
}
static void
w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset, u32 *retryvar)
static int
w_sdreg32(struct brcmf_sdio *bus, u32 regval, u32 reg_offset)
{
u8 idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
*retryvar = 0;
do {
brcmf_sdcard_reg_write(bus->sdiodev,
bus->ci->c_inf[idx].base + reg_offset,
sizeof(u32), regval);
} while (brcmf_sdcard_regfail(bus->sdiodev) &&
(++(*retryvar) <= retry_limit));
if (*retryvar) {
bus->regfails += (*retryvar-1);
if (*retryvar > retry_limit)
brcmf_dbg(ERROR, "FAILED REGISTER WRITE %Xh\n",
reg_offset);
}
int ret;
brcmf_sdio_regwl(bus->sdiodev,
bus->ci->c_inf[idx].base + reg_offset,
regval, &ret);
return ret;
}
#define PKT_AVAILABLE() (intstatus & I_HMB_FRAME_IND)
@ -697,16 +683,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
clkreq =
bus->alp_only ? SBSDIO_ALP_AVAIL_REQ : SBSDIO_HT_AVAIL_REQ;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
clkreq, &err);
if (err) {
brcmf_dbg(ERROR, "HT Avail request error: %d\n", err);
return -EBADE;
}
/* Check current status */
clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
clkctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err) {
brcmf_dbg(ERROR, "HT Avail read error: %d\n", err);
return -EBADE;
@ -715,9 +701,8 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
/* Go to pending and await interrupt if appropriate */
if (!SBSDIO_CLKAV(clkctl, bus->alp_only) && pendok) {
/* Allow only clock-available interrupt */
devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
if (err) {
brcmf_dbg(ERROR, "Devctl error setting CA: %d\n",
err);
@ -725,30 +710,28 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
}
devctl |= SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
devctl, &err);
brcmf_dbg(INFO, "CLKCTL: set PENDING\n");
bus->clkstate = CLK_PENDING;
return 0;
} else if (bus->clkstate == CLK_PENDING) {
/* Cancel CA-only interrupt filter */
devctl =
brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
devctl, &err);
}
/* Otherwise, wait here (polling) for HT Avail */
timeout = jiffies +
msecs_to_jiffies(PMU_MAX_TRANSITION_DLY/1000);
while (!SBSDIO_CLKAV(clkctl, bus->alp_only)) {
clkctl = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
&err);
clkctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR,
&err);
if (time_after(jiffies, timeout))
break;
else
@ -781,17 +764,16 @@ static int brcmf_sdbrcm_htclk(struct brcmf_sdio *bus, bool on, bool pendok)
if (bus->clkstate == CLK_PENDING) {
/* Cancel CA-only interrupt filter */
devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
devctl, &err);
}
bus->clkstate = CLK_SDONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, clkreq, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
clkreq, &err);
brcmf_dbg(INFO, "CLKCTL: turned OFF\n");
if (err) {
brcmf_dbg(ERROR, "Failed access turning clock off: %d\n",
@ -874,7 +856,7 @@ static int brcmf_sdbrcm_clkctl(struct brcmf_sdio *bus, uint target, bool pendok)
static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
{
uint retries = 0;
int ret;
brcmf_dbg(INFO, "request %s (currently %s)\n",
sleep ? "SLEEP" : "WAKE",
@ -894,22 +876,20 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
/* Tell device to start using OOB wakeup */
w_sdreg32(bus, SMB_USE_OOB,
offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
if (retries > retry_limit)
ret = w_sdreg32(bus, SMB_USE_OOB,
offsetof(struct sdpcmd_regs, tosbmailbox));
if (ret != 0)
brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP, WILL NOT WAKE UP!!\n");
/* Turn off our contribution to the HT clock request */
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
SBSDIO_FORCE_HW_CLKREQ_OFF, NULL);
/* Isolate the bus */
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL,
SBSDIO_DEVCTL_PADS_ISO, NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
SBSDIO_DEVCTL_PADS_ISO, NULL);
/* Change state */
bus->sleeping = true;
@ -917,21 +897,20 @@ static int brcmf_sdbrcm_bussleep(struct brcmf_sdio *bus, bool sleep)
} else {
/* Waking up: bus power up is ok, set local state */
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
0, NULL);
/* Make sure the controller has the bus up */
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
/* Send misc interrupt to indicate OOB not needed */
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, tosbmailboxdata),
&retries);
if (retries <= retry_limit)
w_sdreg32(bus, SMB_DEV_INT,
offsetof(struct sdpcmd_regs, tosbmailbox),
&retries);
ret = w_sdreg32(bus, 0,
offsetof(struct sdpcmd_regs, tosbmailboxdata));
if (ret == 0)
ret = w_sdreg32(bus, SMB_DEV_INT,
offsetof(struct sdpcmd_regs, tosbmailbox));
if (retries > retry_limit)
if (ret != 0)
brcmf_dbg(ERROR, "CANNOT SIGNAL CHIP TO CLEAR OOB!!\n");
/* Make sure we have SD bus access */
@ -955,17 +934,17 @@ static u32 brcmf_sdbrcm_hostmail(struct brcmf_sdio *bus)
u32 intstatus = 0;
u32 hmb_data;
u8 fcbits;
uint retries = 0;
int ret;
brcmf_dbg(TRACE, "Enter\n");
/* Read mailbox data and ack that we did so */
r_sdreg32(bus, &hmb_data,
offsetof(struct sdpcmd_regs, tohostmailboxdata), &retries);
ret = r_sdreg32(bus, &hmb_data,
offsetof(struct sdpcmd_regs, tohostmailboxdata));
if (retries <= retry_limit)
if (ret == 0)
w_sdreg32(bus, SMB_INT_ACK,
offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
offsetof(struct sdpcmd_regs, tosbmailbox));
bus->f1regdata += 2;
/* Dongle recomposed rx frames, accept them again */
@ -1040,17 +1019,16 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
if (abort)
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_FRAMECTRL,
SFC_RF_TERM, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
SFC_RF_TERM, &err);
bus->f1regdata++;
/* Wait until the packet has been flushed (device/FIFO stable) */
for (lastrbc = retries = 0xffff; retries > 0; retries--) {
hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_RFRAMEBCHI, NULL);
lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_RFRAMEBCLO, NULL);
hi = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_RFRAMEBCHI, &err);
lo = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_RFRAMEBCLO, &err);
bus->f1regdata += 2;
if ((hi == 0) && (lo == 0))
@ -1070,11 +1048,11 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
if (rtx) {
bus->rxrtx++;
w_sdreg32(bus, SMB_NAK,
offsetof(struct sdpcmd_regs, tosbmailbox), &retries);
err = w_sdreg32(bus, SMB_NAK,
offsetof(struct sdpcmd_regs, tosbmailbox));
bus->f1regdata++;
if (retries <= retry_limit)
if (err == 0)
bus->rxskip = true;
}
@ -1082,7 +1060,7 @@ static void brcmf_sdbrcm_rxfail(struct brcmf_sdio *bus, bool abort, bool rtx)
bus->nextlen = 0;
/* If we can't reach the device, signal failure */
if (err || brcmf_sdcard_regfail(bus->sdiodev))
if (err)
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
}
@ -2178,21 +2156,16 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
bus->tx_sderrs++;
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
SFC_WF_TERM, NULL);
bus->f1regdata++;
for (i = 0; i < 3; i++) {
u8 hi, lo;
hi = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_FUNC1_WFRAMEBCHI,
NULL);
lo = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_FUNC1_WFRAMEBCLO,
NULL);
hi = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCHI, NULL);
lo = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCLO, NULL);
bus->f1regdata += 2;
if ((hi == 0) && (lo == 0))
break;
@ -2219,7 +2192,6 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
{
struct sk_buff *pkt;
u32 intstatus = 0;
uint retries = 0;
int ret = 0, prec_out;
uint cnt = 0;
uint datalen;
@ -2249,11 +2221,11 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
/* In poll mode, need to check for other events */
if (!bus->intr && cnt) {
/* Check device status, signal pending interrupt */
r_sdreg32(bus, &intstatus,
offsetof(struct sdpcmd_regs, intstatus),
&retries);
ret = r_sdreg32(bus, &intstatus,
offsetof(struct sdpcmd_regs,
intstatus));
bus->f2txdata++;
if (brcmf_sdcard_regfail(bus->sdiodev))
if (ret != 0)
break;
if (intstatus & bus->hostintmask)
bus->ipend = true;
@ -2275,7 +2247,6 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
{
u32 local_hostintmask;
u8 saveclk;
uint retries;
int err;
struct brcmf_bus *bus_if = dev_get_drvdata(dev);
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
@ -2303,7 +2274,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
/* Disable and clear interrupts at the chip level also */
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask), &retries);
w_sdreg32(bus, 0, offsetof(struct sdpcmd_regs, hostintmask));
local_hostintmask = bus->hostintmask;
bus->hostintmask = 0;
@ -2311,24 +2282,23 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
/* Force clocks on backplane to be sure F2 interrupt propagates */
saveclk = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
saveclk = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (!err) {
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
(saveclk | SBSDIO_FORCE_HT), &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
(saveclk | SBSDIO_FORCE_HT), &err);
}
if (err)
brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
/* Turn off the bus (F2), free any pending packets */
brcmf_dbg(INTR, "disable SDIO interrupts\n");
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
SDIO_FUNC_ENABLE_1, NULL);
brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, SDIO_FUNC_ENABLE_1,
NULL);
/* Clear any pending interrupts now that F2 is disabled */
w_sdreg32(bus, local_hostintmask,
offsetof(struct sdpcmd_regs, intstatus), &retries);
offsetof(struct sdpcmd_regs, intstatus));
/* Turn off the backplane clock (only) */
brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
@ -2373,12 +2343,12 @@ static inline void brcmf_sdbrcm_clrintr(struct brcmf_sdio *bus)
static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
{
u32 intstatus, newstatus = 0;
uint retries = 0;
uint rxlimit = bus->rxbound; /* Rx frames to read before resched */
uint txlimit = bus->txbound; /* Tx frames to send before resched */
uint framecnt = 0; /* Temporary counter of tx/rx frames */
bool rxdone = true; /* Flag for no more read data */
bool resched = false; /* Flag indicating resched wanted */
int err;
brcmf_dbg(TRACE, "Enter\n");
@ -2389,13 +2359,12 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
/* If waiting for HTAVAIL, check status */
if (bus->clkstate == CLK_PENDING) {
int err;
u8 clkctl, devctl = 0;
#ifdef DEBUG
/* Check for inconsistent device control */
devctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
if (err) {
brcmf_dbg(ERROR, "error reading DEVCTL: %d\n", err);
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
@ -2403,8 +2372,8 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
#endif /* DEBUG */
/* Read CSR, if clock on switch to AVAIL, else ignore */
clkctl = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
clkctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err) {
brcmf_dbg(ERROR, "error reading CSR: %d\n",
err);
@ -2415,17 +2384,16 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
devctl, clkctl);
if (SBSDIO_HTAV(clkctl)) {
devctl = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, &err);
devctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_DEVICE_CTL, &err);
if (err) {
brcmf_dbg(ERROR, "error reading DEVCTL: %d\n",
err);
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
}
devctl &= ~SBSDIO_DEVCTL_CA_INT_ONLY;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_DEVICE_CTL, devctl, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_DEVICE_CTL,
devctl, &err);
if (err) {
brcmf_dbg(ERROR, "error writing DEVCTL: %d\n",
err);
@ -2447,17 +2415,17 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
/* Pending interrupt indicates new device status */
if (bus->ipend) {
bus->ipend = false;
r_sdreg32(bus, &newstatus,
offsetof(struct sdpcmd_regs, intstatus), &retries);
err = r_sdreg32(bus, &newstatus,
offsetof(struct sdpcmd_regs, intstatus));
bus->f1regdata++;
if (brcmf_sdcard_regfail(bus->sdiodev))
if (err != 0)
newstatus = 0;
newstatus &= bus->hostintmask;
bus->fcstate = !!(newstatus & I_HMB_FC_STATE);
if (newstatus) {
w_sdreg32(bus, newstatus,
offsetof(struct sdpcmd_regs, intstatus),
&retries);
err = w_sdreg32(bus, newstatus,
offsetof(struct sdpcmd_regs,
intstatus));
bus->f1regdata++;
}
}
@ -2472,11 +2440,11 @@ static bool brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
*/
if (intstatus & I_HMB_FC_CHANGE) {
intstatus &= ~I_HMB_FC_CHANGE;
w_sdreg32(bus, I_HMB_FC_CHANGE,
offsetof(struct sdpcmd_regs, intstatus), &retries);
err = w_sdreg32(bus, I_HMB_FC_CHANGE,
offsetof(struct sdpcmd_regs, intstatus));
r_sdreg32(bus, &newstatus,
offsetof(struct sdpcmd_regs, intstatus), &retries);
err = r_sdreg32(bus, &newstatus,
offsetof(struct sdpcmd_regs, intstatus));
bus->f1regdata += 2;
bus->fcstate =
!!(newstatus & (I_HMB_FC_STATE | I_HMB_FC_CHANGE));
@ -2546,21 +2514,18 @@ clkwait:
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_FRAMECTRL, SFC_WF_TERM,
NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
SFC_WF_TERM, &err);
bus->f1regdata++;
for (i = 0; i < 3; i++) {
u8 hi, lo;
hi = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_FUNC1_WFRAMEBCHI,
NULL);
lo = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_1,
SBSDIO_FUNC1_WFRAMEBCLO,
NULL);
hi = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCHI,
&err);
lo = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCLO,
&err);
bus->f1regdata += 2;
if ((hi == 0) && (lo == 0))
break;
@ -2587,10 +2552,8 @@ clkwait:
else await next interrupt */
/* On failed register access, all bets are off:
no resched or interrupts */
if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) ||
brcmf_sdcard_regfail(bus->sdiodev)) {
brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation %d\n",
brcmf_sdcard_regfail(bus->sdiodev));
if ((bus->sdiodev->bus_if->state == BRCMF_BUS_DOWN) || (err != 0)) {
brcmf_dbg(ERROR, "failed backplane access over SDIO, halting operation\n");
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
bus->intstatus = 0;
} else if (bus->clkstate == CLK_PENDING) {
@ -2886,19 +2849,16 @@ static int brcmf_tx_frame(struct brcmf_sdio *bus, u8 *frame, u16 len)
brcmf_sdcard_abort(bus->sdiodev, SDIO_FUNC_2);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_FRAMECTRL,
SFC_WF_TERM, NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_FRAMECTRL,
SFC_WF_TERM, NULL);
bus->f1regdata++;
for (i = 0; i < 3; i++) {
u8 hi, lo;
hi = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_WFRAMEBCHI,
NULL);
lo = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_WFRAMEBCLO,
NULL);
hi = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCHI, NULL);
lo = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_WFRAMEBCLO, NULL);
bus->f1regdata += 2;
if (hi == 0 && lo == 0)
break;
@ -3188,7 +3148,6 @@ static int brcmf_sdbrcm_write_vars(struct brcmf_sdio *bus)
static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
{
uint retries;
int bcmerror = 0;
struct chip_info *ci = bus->ci;
@ -3222,7 +3181,7 @@ static int brcmf_sdbrcm_download_state(struct brcmf_sdio *bus, bool enter)
}
w_sdreg32(bus, 0xFFFFFFFF,
offsetof(struct sdpcmd_regs, intstatus), &retries);
offsetof(struct sdpcmd_regs, intstatus));
ci->resetcore(bus->sdiodev, ci, BCMA_CORE_ARM_CM3);
@ -3444,7 +3403,6 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
struct brcmf_sdio *bus = sdiodev->bus;
unsigned long timeout;
uint retries = 0;
u8 ready, enable;
int err, ret = 0;
u8 saveclk;
@ -3472,13 +3430,11 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
goto exit;
/* Force clocks on backplane to be sure F2 interrupt propagates */
saveclk =
brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
saveclk = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (!err) {
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
(saveclk | SBSDIO_FORCE_HT), &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
(saveclk | SBSDIO_FORCE_HT), &err);
}
if (err) {
brcmf_dbg(ERROR, "Failed to force clock for F2: err %d\n", err);
@ -3487,17 +3443,16 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
/* Enable function 2 (frame transfers) */
w_sdreg32(bus, SDPCM_PROT_VERSION << SMB_DATA_VERSION_SHIFT,
offsetof(struct sdpcmd_regs, tosbmailboxdata), &retries);
offsetof(struct sdpcmd_regs, tosbmailboxdata));
enable = (SDIO_FUNC_ENABLE_1 | SDIO_FUNC_ENABLE_2);
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
enable, NULL);
brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL);
timeout = jiffies + msecs_to_jiffies(BRCMF_WAIT_F2RDY);
ready = 0;
while (enable != ready) {
ready = brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_0,
SDIO_CCCR_IORx, NULL);
ready = brcmf_sdio_regrb(bus->sdiodev,
SDIO_CCCR_IORx, NULL);
if (time_after(jiffies, timeout))
break;
else if (time_after(jiffies, timeout - BRCMF_WAIT_F2RDY + 50))
@ -3512,21 +3467,18 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
/* Set up the interrupt mask and enable interrupts */
bus->hostintmask = HOSTINTMASK;
w_sdreg32(bus, bus->hostintmask,
offsetof(struct sdpcmd_regs, hostintmask), &retries);
offsetof(struct sdpcmd_regs, hostintmask));
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_WATERMARK, 8, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_WATERMARK, 8, &err);
} else {
/* Disable F2 again */
enable = SDIO_FUNC_ENABLE_1;
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0,
SDIO_CCCR_IOEx, enable, NULL);
brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx, enable, NULL);
ret = -ENODEV;
}
/* Restore previous clock setting */
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, saveclk, &err);
if (ret == 0) {
ret = brcmf_sdio_intr_register(bus->sdiodev);
@ -3606,9 +3558,9 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
if (!bus->dpc_sched) {
u8 devpend;
devpend = brcmf_sdcard_cfg_read(bus->sdiodev,
SDIO_FUNC_0, SDIO_CCCR_INTx,
NULL);
devpend = brcmf_sdio_regrb(bus->sdiodev,
SDIO_CCCR_INTx,
NULL);
intstatus =
devpend & (INTR_STATUS_FUNC1 |
INTR_STATUS_FUNC2);
@ -3732,24 +3684,18 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
bus->alp_only = true;
/* Return the window to backplane enumeration space for core access */
if (brcmf_sdcard_set_sbaddr_window(bus->sdiodev, SI_ENUM_BASE))
brcmf_dbg(ERROR, "FAILED to return to SI_ENUM_BASE\n");
pr_debug("F1 signature read @0x18000000=0x%4x\n",
brcmf_sdcard_reg_read(bus->sdiodev, SI_ENUM_BASE, 4));
brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
/*
* Force PLL off until brcmf_sdio_chip_attach()
* programs PLL control regs
*/
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR,
BRCMF_INIT_CLKCTL1, &err);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR,
BRCMF_INIT_CLKCTL1, &err);
if (!err)
clkctl =
brcmf_sdcard_cfg_read(bus->sdiodev, SDIO_FUNC_1,
clkctl = brcmf_sdio_regrb(bus->sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, &err);
if (err || ((clkctl & ~SBSDIO_AVBITS) != BRCMF_INIT_CLKCTL1)) {
@ -3782,9 +3728,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
idx = brcmf_sdio_chip_getinfidx(bus->ci, BCMA_CORE_SDIO_DEV);
reg_addr = bus->ci->c_inf[idx].base +
offsetof(struct sdpcmd_regs, corecontrol);
reg_val = brcmf_sdcard_reg_read(bus->sdiodev, reg_addr, sizeof(u32));
brcmf_sdcard_reg_write(bus->sdiodev, reg_addr, sizeof(u32),
reg_val | CC_BPRESEN);
reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL);
brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL);
brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
@ -3809,16 +3754,15 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
brcmf_dbg(TRACE, "Enter\n");
/* Disable F2 to clear any intermediate frame state on the dongle */
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_0, SDIO_CCCR_IOEx,
SDIO_FUNC_ENABLE_1, NULL);
brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx,
SDIO_FUNC_ENABLE_1, NULL);
bus->sdiodev->bus_if->state = BRCMF_BUS_DOWN;
bus->sleeping = false;
bus->rxflow = false;
/* Done with backplane-dependent accesses, can drop clock... */
brcmf_sdcard_cfg_write(bus->sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
/* ...and initialize clock/power states */
bus->clkstate = CLK_SDONLY;

View File

@ -93,8 +93,9 @@ brcmf_sdio_sb_corerev(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbidhigh), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbidhigh),
NULL);
return SBCOREREV(regdata);
}
@ -118,8 +119,9 @@ brcmf_sdio_sb_iscoreup(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
regdata &= (SSB_TMSLOW_RESET | SSB_TMSLOW_REJECT |
SSB_IMSTATE_REJECT | SSB_TMSLOW_CLOCK);
return (SSB_TMSLOW_CLOCK == regdata);
@ -135,13 +137,13 @@ brcmf_sdio_ai_iscoreup(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
ret = (regdata & (BCMA_IOCTL_FGC | BCMA_IOCTL_CLK)) == BCMA_IOCTL_CLK;
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
4);
regdata = brcmf_sdio_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
NULL);
ret = ret && ((regdata & BCMA_RESET_CTL_RESET) == 0);
return ret;
@ -151,84 +153,85 @@ static void
brcmf_sdio_sb_coredisable(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci, u16 coreid)
{
u32 regdata;
u32 regdata, base;
u8 idx;
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
base = ci->c_inf[idx].base;
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
if (regdata & SSB_TMSLOW_RESET)
return;
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow), NULL);
if ((regdata & SSB_TMSLOW_CLOCK) != 0) {
/*
* set target reject and spin until busy is clear
* (preserve core-specific bits)
*/
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
4, regdata | SSB_TMSLOW_REJECT);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
NULL);
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
regdata | SSB_TMSLOW_REJECT, NULL);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
NULL);
udelay(1);
SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4) &
SPINWAIT((brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbtmstatehigh),
NULL) &
SSB_TMSHIGH_BUSY), 100000);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbtmstatehigh),
NULL);
if (regdata & SSB_TMSHIGH_BUSY)
brcmf_dbg(ERROR, "core state still busy\n");
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
NULL);
if (regdata & SSB_IDLOW_INITIATOR) {
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4) |
SSB_IMSTATE_REJECT;
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
regdata);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
regdata |= SSB_IMSTATE_REJECT;
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
regdata, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
udelay(1);
SPINWAIT((brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
SPINWAIT((brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL) &
SSB_IMSTATE_BUSY), 100000);
}
/* set reset and reject while enabling the clocks */
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
(SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
regdata = SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK |
SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET;
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
regdata, NULL);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbtmstatelow),
NULL);
udelay(10);
/* clear the initiator reject bit */
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbidlow), 4);
regdata = brcmf_sdio_regrl(sdiodev, CORE_SB(base, sbidlow),
NULL);
if (regdata & SSB_IDLOW_INITIATOR) {
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4) &
~SSB_IMSTATE_REJECT;
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
regdata);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(base, sbimstate),
NULL);
regdata &= ~SSB_IMSTATE_REJECT;
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbimstate),
regdata, NULL);
}
}
/* leave reset and reject asserted */
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
(SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET));
brcmf_sdio_regwl(sdiodev, CORE_SB(base, sbtmstatelow),
(SSB_TMSLOW_REJECT | SSB_TMSLOW_RESET), NULL);
udelay(1);
}
@ -242,20 +245,19 @@ brcmf_sdio_ai_coredisable(struct brcmf_sdio_dev *sdiodev,
idx = brcmf_sdio_chip_getinfidx(ci, coreid);
/* if core is already in reset, just return */
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
4);
regdata = brcmf_sdio_regrl(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
NULL);
if ((regdata & BCMA_RESET_CTL_RESET) != 0)
return;
brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
4, 0);
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL, 0, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
udelay(10);
brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
4, BCMA_RESET_CTL_RESET);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
BCMA_RESET_CTL_RESET, NULL);
udelay(1);
}
@ -279,41 +281,47 @@ brcmf_sdio_sb_resetcore(struct brcmf_sdio_dev *sdiodev,
* set reset while enabling the clock and
* forcing them on throughout the core
*/
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
brcmf_sdio_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK | SSB_TMSLOW_RESET,
NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
udelay(1);
/* clear any serror */
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
NULL);
if (regdata & SSB_TMSHIGH_SERR)
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh), 4, 0);
brcmf_sdio_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatehigh),
0, NULL);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate),
NULL);
if (regdata & (SSB_IMSTATE_IBE | SSB_IMSTATE_TO))
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate), 4,
regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO));
brcmf_sdio_regwl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbimstate),
regdata & ~(SSB_IMSTATE_IBE | SSB_IMSTATE_TO),
NULL);
/* clear reset and allow it to propagate throughout the core */
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4,
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_FGC | SSB_TMSLOW_CLOCK, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
udelay(1);
/* leave clock enabled */
brcmf_sdcard_reg_write(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
4, SSB_TMSLOW_CLOCK);
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow), 4);
brcmf_sdio_regwl(sdiodev, CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
SSB_TMSLOW_CLOCK, NULL);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_SB(ci->c_inf[idx].base, sbtmstatelow),
NULL);
udelay(1);
}
@ -330,18 +338,18 @@ brcmf_sdio_ai_resetcore(struct brcmf_sdio_dev *sdiodev,
brcmf_sdio_ai_coredisable(sdiodev, ci, coreid);
/* now do initialization sequence */
brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
4, BCMA_IOCTL_FGC | BCMA_IOCTL_CLK);
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
4, 0);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
BCMA_IOCTL_FGC | BCMA_IOCTL_CLK, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_RESET_CTL,
0, NULL);
udelay(1);
brcmf_sdcard_reg_write(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
4, BCMA_IOCTL_CLK);
regdata = brcmf_sdcard_reg_read(sdiodev,
ci->c_inf[idx].wrapbase+BCMA_IOCTL, 4);
brcmf_sdio_regwl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
BCMA_IOCTL_CLK, NULL);
regdata = brcmf_sdio_regrl(sdiodev, ci->c_inf[idx].wrapbase+BCMA_IOCTL,
NULL);
udelay(1);
}
@ -358,8 +366,9 @@ static int brcmf_sdio_chip_recognition(struct brcmf_sdio_dev *sdiodev,
*/
ci->c_inf[0].id = BCMA_CORE_CHIPCOMMON;
ci->c_inf[0].base = regs;
regdata = brcmf_sdcard_reg_read(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipid), 4);
regdata = brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipid),
NULL);
ci->chip = regdata & CID_ID_MASK;
ci->chiprev = (regdata & CID_REV_MASK) >> CID_REV_SHIFT;
ci->socitype = (regdata & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
@ -428,8 +437,7 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
/* Try forcing SDIO core to do ALPAvail request only */
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_ALP_AVAIL_REQ;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
if (err) {
brcmf_dbg(ERROR, "error writing for HT off\n");
return err;
@ -437,8 +445,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
/* If register supported, wait for ALPAvail and then force ALP */
/* This may take up to 15 milliseconds */
clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, NULL);
clkval = brcmf_sdio_regrb(sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, NULL);
if ((clkval & ~SBSDIO_AVBITS) != clkset) {
brcmf_dbg(ERROR, "ChipClkCSR access: wrote 0x%02x read 0x%02x\n",
@ -446,8 +454,8 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
return -EACCES;
}
SPINWAIT(((clkval = brcmf_sdcard_cfg_read(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
SPINWAIT(((clkval = brcmf_sdio_regrb(sdiodev,
SBSDIO_FUNC1_CHIPCLKCSR, NULL)),
!SBSDIO_ALPAV(clkval)),
PMU_MAX_TRANSITION_DLY);
if (!SBSDIO_ALPAV(clkval)) {
@ -457,13 +465,11 @@ brcmf_sdio_chip_buscoreprep(struct brcmf_sdio_dev *sdiodev)
}
clkset = SBSDIO_FORCE_HW_CLKREQ_OFF | SBSDIO_FORCE_ALP;
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, clkset, &err);
udelay(65);
/* Also, disable the extra SDIO pull-ups */
brcmf_sdcard_cfg_write(sdiodev, SDIO_FUNC_1,
SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
brcmf_sdio_regwb(sdiodev, SBSDIO_FUNC1_SDIOPULLUP, 0, NULL);
return 0;
}
@ -472,18 +478,22 @@ static void
brcmf_sdio_chip_buscoresetup(struct brcmf_sdio_dev *sdiodev,
struct chip_info *ci)
{
u32 base = ci->c_inf[0].base;
/* get chipcommon rev */
ci->c_inf[0].rev = ci->corerev(sdiodev, ci, ci->c_inf[0].id);
/* get chipcommon capabilites */
ci->c_inf[0].caps =
brcmf_sdcard_reg_read(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, capabilities), 4);
ci->c_inf[0].caps = brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(base, capabilities),
NULL);
/* get pmu caps & rev */
if (ci->c_inf[0].caps & CC_CAP_PMU) {
ci->pmucaps = brcmf_sdcard_reg_read(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, pmucapabilities), 4);
ci->pmucaps =
brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(base, pmucapabilities),
NULL);
ci->pmurev = ci->pmucaps & PCAP_REV_MASK;
}
@ -523,10 +533,10 @@ int brcmf_sdio_chip_attach(struct brcmf_sdio_dev *sdiodev,
brcmf_sdio_chip_buscoresetup(sdiodev, ci);
brcmf_sdcard_reg_write(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, gpiopullup), 4, 0);
brcmf_sdcard_reg_write(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, gpiopulldown), 4, 0);
brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopullup),
0, NULL);
brcmf_sdio_regwl(sdiodev, CORE_CC_REG(ci->c_inf[0].base, gpiopulldown),
0, NULL);
*ci_ptr = ci;
return 0;
@ -562,6 +572,7 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
u32 str_mask = 0;
u32 str_shift = 0;
char chn[8];
u32 base = ci->c_inf[0].base;
if (!(ci->c_inf[0].caps & CC_CAP_PMU))
return;
@ -591,17 +602,17 @@ brcmf_sdio_chip_drivestrengthinit(struct brcmf_sdio_dev *sdiodev,
}
}
brcmf_sdcard_reg_write(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
4, 1);
cc_data_temp = brcmf_sdcard_reg_read(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr), 4);
brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr),
1, NULL);
cc_data_temp =
brcmf_sdio_regrl(sdiodev,
CORE_CC_REG(base, chipcontrol_addr),
NULL);
cc_data_temp &= ~str_mask;
drivestrength_sel <<= str_shift;
cc_data_temp |= drivestrength_sel;
brcmf_sdcard_reg_write(sdiodev,
CORE_CC_REG(ci->c_inf[0].base, chipcontrol_addr),
4, cc_data_temp);
brcmf_sdio_regwl(sdiodev, CORE_CC_REG(base, chipcontrol_addr),
cc_data_temp, NULL);
brcmf_dbg(INFO, "SDIO: %dmA drive strength selected, set to 0x%08x\n",
drivestrength, cc_data_temp);

View File

@ -40,6 +40,10 @@
/* Maximum number of I/O funcs */
#define SDIOD_MAX_IOFUNCS 7
/* mask of register map */
#define REG_F0_REG_MASK 0x7FF
#define REG_F1_MISC_MASK 0x1FFFF
/* as of sdiod rev 0, supports 3 functions */
#define SBSDIO_NUM_FUNCTION 3
@ -142,7 +146,6 @@ struct brcmf_sdio_dev {
u8 num_funcs; /* Supported funcs on client */
u32 func_cis_ptr[SDIOD_MAX_IOFUNCS];
u32 sbwad; /* Save backplane window address */
bool regfail; /* status of last reg_r/w call */
void *bus;
atomic_t suspend; /* suspend flag */
wait_queue_head_t request_byte_wait;
@ -164,31 +167,13 @@ struct brcmf_sdio_dev {
extern int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev);
extern int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev);
/* Access SDIO address space (e.g. CCCR) using CMD52 (single-byte interface).
* fn: function number
* addr: unmodified SDIO-space address
* data: data byte to write
* err: pointer to error code (or NULL)
*/
extern u8 brcmf_sdcard_cfg_read(struct brcmf_sdio_dev *sdiodev, uint func,
u32 addr, int *err);
extern void brcmf_sdcard_cfg_write(struct brcmf_sdio_dev *sdiodev, uint func,
u32 addr, u8 data, int *err);
/* Synchronous access to device (client) core registers via CMD53 to F1.
* addr: backplane address (i.e. >= regsva from attach)
* size: register width in bytes (2 or 4)
* data: data for register write
*/
extern u32
brcmf_sdcard_reg_read(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size);
extern u32
brcmf_sdcard_reg_write(struct brcmf_sdio_dev *sdiodev, u32 addr, uint size,
u32 data);
/* Indicate if last reg read/write failed */
extern bool brcmf_sdcard_regfail(struct brcmf_sdio_dev *sdiodev);
/* sdio device register access interface */
extern u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
extern u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret);
extern void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
u8 data, int *ret);
extern void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
u32 data, int *ret);
/* Buffer transfer to/from device (client) core via cmd53.
* fn: function number

View File

@ -39,10 +39,7 @@ BRCMSMAC_OFILES := \
phy/phytbl_lcn.o \
phy/phytbl_n.o \
phy/phy_qmath.o \
otp.o \
srom.o \
dma.o \
nicpci.o \
brcms_trace_events.o
MODULEPFX := brcmsmac

View File

@ -19,7 +19,6 @@
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/delay.h>
#include <linux/pci.h>
#include <defs.h>
#include <chipcommon.h>
@ -29,8 +28,6 @@
#include "types.h"
#include "pub.h"
#include "pmu.h"
#include "srom.h"
#include "nicpci.h"
#include "aiutils.h"
/* slow_clk_ctl */
@ -321,7 +318,6 @@
#define IS_SIM(chippkg) \
((chippkg == HDLSIM_PKG_ID) || (chippkg == HWSIM_PKG_ID))
#define PCI(sih) (ai_get_buscoretype(sih) == PCI_CORE_ID)
#define PCIE(sih) (ai_get_buscoretype(sih) == PCIE_CORE_ID)
#define PCI_FORCEHT(sih) (PCIE(sih) && (ai_get_chip_id(sih) == BCM4716_CHIP_ID))
@ -454,36 +450,9 @@ struct aidmp {
u32 componentid3; /* 0xffc */
};
/* return true if PCIE capability exists in the pci config space */
static bool ai_ispcie(struct si_info *sii)
{
u8 cap_ptr;
cap_ptr =
pcicore_find_pci_capability(sii->pcibus, PCI_CAP_ID_EXP, NULL,
NULL);
if (!cap_ptr)
return false;
return true;
}
static bool ai_buscore_prep(struct si_info *sii)
{
/* kludge to enable the clock on the 4306 which lacks a slowclock */
if (!ai_ispcie(sii))
ai_clkctl_xtal(&sii->pub, XTAL | PLL, ON);
return true;
}
static bool
ai_buscore_setup(struct si_info *sii, struct bcma_device *cc)
{
struct bcma_device *pci = NULL;
struct bcma_device *pcie = NULL;
struct bcma_device *core;
/* no cores found, bail out */
if (cc->bus->nr_cores == 0)
return false;
@ -492,8 +461,7 @@ ai_buscore_setup(struct si_info *sii, struct bcma_device *cc)
sii->pub.ccrev = cc->id.rev;
/* get chipcommon chipstatus */
if (ai_get_ccrev(&sii->pub) >= 11)
sii->chipst = bcma_read32(cc, CHIPCREGOFFS(chipstatus));
sii->chipst = bcma_read32(cc, CHIPCREGOFFS(chipstatus));
/* get chipcommon capabilites */
sii->pub.cccaps = bcma_read32(cc, CHIPCREGOFFS(capabilities));
@ -506,64 +474,18 @@ ai_buscore_setup(struct si_info *sii, struct bcma_device *cc)
}
/* figure out buscore */
list_for_each_entry(core, &cc->bus->cores, list) {
uint cid, crev;
cid = core->id.id;
crev = core->id.rev;
if (cid == PCI_CORE_ID) {
pci = core;
} else if (cid == PCIE_CORE_ID) {
pcie = core;
}
}
if (pci && pcie) {
if (ai_ispcie(sii))
pci = NULL;
else
pcie = NULL;
}
if (pci) {
sii->buscore = pci;
} else if (pcie) {
sii->buscore = pcie;
}
/* fixup necessary chip/core configurations */
if (!sii->pch) {
sii->pch = pcicore_init(&sii->pub, sii->icbus->drv_pci.core);
if (sii->pch == NULL)
return false;
}
if (ai_pci_fixcfg(&sii->pub))
return false;
sii->buscore = ai_findcore(&sii->pub, PCIE_CORE_ID, 0);
return true;
}
/*
* get boardtype and boardrev
*/
static __used void ai_nvram_process(struct si_info *sii)
{
uint w = 0;
/* do a pci config read to get subsystem id and subvendor id */
pci_read_config_dword(sii->pcibus, PCI_SUBSYSTEM_VENDOR_ID, &w);
sii->pub.boardvendor = w & 0xffff;
sii->pub.boardtype = (w >> 16) & 0xffff;
}
static struct si_info *ai_doattach(struct si_info *sii,
struct bcma_bus *pbus)
{
struct si_pub *sih = &sii->pub;
u32 w, savewin;
struct bcma_device *cc;
uint socitype;
struct ssb_sprom *sprom = &pbus->sprom;
savewin = 0;
@ -573,38 +495,15 @@ static struct si_info *ai_doattach(struct si_info *sii,
/* switch to Chipcommon core */
cc = pbus->drv_cc.core;
/* bus/core/clk setup for register access */
if (!ai_buscore_prep(sii))
return NULL;
sih->chip = pbus->chipinfo.id;
sih->chiprev = pbus->chipinfo.rev;
sih->chippkg = pbus->chipinfo.pkg;
sih->boardvendor = pbus->boardinfo.vendor;
sih->boardtype = pbus->boardinfo.type;
/*
* ChipID recognition.
* We assume we can read chipid at offset 0 from the regs arg.
* If we add other chiptypes (or if we need to support old sdio
* hosts w/o chipcommon), some way of recognizing them needs to
* be added here.
*/
w = bcma_read32(cc, CHIPCREGOFFS(chipid));
socitype = (w & CID_TYPE_MASK) >> CID_TYPE_SHIFT;
/* Might as wll fill in chip id rev & pkg */
sih->chip = w & CID_ID_MASK;
sih->chiprev = (w & CID_REV_MASK) >> CID_REV_SHIFT;
sih->chippkg = (w & CID_PKG_MASK) >> CID_PKG_SHIFT;
/* scan for cores */
if (socitype != SOCI_AI)
return NULL;
SI_MSG("Found chip type AI (0x%08x)\n", w);
if (!ai_buscore_setup(sii, cc))
goto exit;
/* Init nvram from sprom/otp if they exist */
if (srom_var_init(&sii->pub))
goto exit;
ai_nvram_process(sii);
/* === NVRAM, clock is ready === */
bcma_write32(cc, CHIPCREGOFFS(gpiopullup), 0);
bcma_write32(cc, CHIPCREGOFFS(gpiopulldown), 0);
@ -617,15 +516,13 @@ static struct si_info *ai_doattach(struct si_info *sii,
}
/* setup the GPIO based LED powersave register */
w = getintvar(sih, BRCMS_SROM_LEDDC);
w = (sprom->leddc_on_time << BCMA_CC_GPIOTIMER_ONTIME_SHIFT) |
(sprom->leddc_off_time << BCMA_CC_GPIOTIMER_OFFTIME_SHIFT);
if (w == 0)
w = DEFAULT_GPIOTIMERVAL;
ai_cc_reg(sih, offsetof(struct chipcregs, gpiotimerval),
~0, w);
if (PCIE(sih))
pcicore_attach(sii->pch, SI_DOATTACH);
if (ai_get_chip_id(sih) == BCM43224_CHIP_ID) {
/*
* enable 12 mA drive strenth for 43224 and
@ -659,9 +556,6 @@ static struct si_info *ai_doattach(struct si_info *sii,
return sii;
exit:
if (sii->pch)
pcicore_deinit(sii->pch);
sii->pch = NULL;
return NULL;
}
@ -700,11 +594,6 @@ void ai_detach(struct si_pub *sih)
if (sii == NULL)
return;
if (sii->pch)
pcicore_deinit(sii->pch);
sii->pch = NULL;
srom_free_vars(sih);
kfree(sii);
}
@ -755,21 +644,7 @@ uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val)
/* return the slow clock source - LPO, XTAL, or PCI */
static uint ai_slowclk_src(struct si_pub *sih, struct bcma_device *cc)
{
struct si_info *sii;
u32 val;
sii = (struct si_info *)sih;
if (ai_get_ccrev(&sii->pub) < 6) {
pci_read_config_dword(sii->pcibus, PCI_GPIO_OUT,
&val);
if (val & PCI_CFG_GPIO_SCS)
return SCC_SS_PCI;
return SCC_SS_XTAL;
} else if (ai_get_ccrev(&sii->pub) < 10) {
return bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)) &
SCC_SS_MASK;
} else /* Insta-clock */
return SCC_SS_XTAL;
return SCC_SS_XTAL;
}
/*
@ -779,36 +654,12 @@ static uint ai_slowclk_src(struct si_pub *sih, struct bcma_device *cc)
static uint ai_slowclk_freq(struct si_pub *sih, bool max_freq,
struct bcma_device *cc)
{
u32 slowclk;
uint div;
slowclk = ai_slowclk_src(sih, cc);
if (ai_get_ccrev(sih) < 6) {
if (slowclk == SCC_SS_PCI)
return max_freq ? (PCIMAXFREQ / 64)
: (PCIMINFREQ / 64);
else
return max_freq ? (XTALMAXFREQ / 32)
: (XTALMINFREQ / 32);
} else if (ai_get_ccrev(sih) < 10) {
div = 4 *
(((bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl)) &
SCC_CD_MASK) >> SCC_CD_SHIFT) + 1);
if (slowclk == SCC_SS_LPO)
return max_freq ? LPOMAXFREQ : LPOMINFREQ;
else if (slowclk == SCC_SS_XTAL)
return max_freq ? (XTALMAXFREQ / div)
: (XTALMINFREQ / div);
else if (slowclk == SCC_SS_PCI)
return max_freq ? (PCIMAXFREQ / div)
: (PCIMINFREQ / div);
} else {
/* Chipc rev 10 is InstaClock */
div = bcma_read32(cc, CHIPCREGOFFS(system_clk_ctl));
div = 4 * ((div >> SYCC_CD_SHIFT) + 1);
return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div);
}
return 0;
/* Chipc rev 10 is InstaClock */
div = bcma_read32(cc, CHIPCREGOFFS(system_clk_ctl));
div = 4 * ((div >> SYCC_CD_SHIFT) + 1);
return max_freq ? XTALMAXFREQ : (XTALMINFREQ / div);
}
static void
@ -831,8 +682,7 @@ ai_clkctl_setdelay(struct si_pub *sih, struct bcma_device *cc)
/* Starting with 4318 it is ILP that is used for the delays */
slowmaxfreq =
ai_slowclk_freq(sih,
(ai_get_ccrev(sih) >= 10) ? false : true, cc);
ai_slowclk_freq(sih, false, cc);
pll_on_delay = ((slowmaxfreq * pll_delay) + 999999) / 1000000;
fref_sel_delay = ((slowmaxfreq * FREF_DELAY) + 999999) / 1000000;
@ -854,9 +704,8 @@ void ai_clkctl_init(struct si_pub *sih)
return;
/* set all Instaclk chip ILP to 1 MHz */
if (ai_get_ccrev(sih) >= 10)
bcma_maskset32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_CD_MASK,
(ILP_DIV_1MHZ << SYCC_CD_SHIFT));
bcma_maskset32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_CD_MASK,
(ILP_DIV_1MHZ << SYCC_CD_SHIFT));
ai_clkctl_setdelay(sih, cc);
}
@ -891,140 +740,6 @@ u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih)
return fpdelay;
}
/* turn primary xtal and/or pll off/on */
int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on)
{
struct si_info *sii;
u32 in, out, outen;
sii = (struct si_info *)sih;
/* pcie core doesn't have any mapping to control the xtal pu */
if (PCIE(sih))
return -1;
pci_read_config_dword(sii->pcibus, PCI_GPIO_IN, &in);
pci_read_config_dword(sii->pcibus, PCI_GPIO_OUT, &out);
pci_read_config_dword(sii->pcibus, PCI_GPIO_OUTEN, &outen);
/*
* Avoid glitching the clock if GPRS is already using it.
* We can't actually read the state of the PLLPD so we infer it
* by the value of XTAL_PU which *is* readable via gpioin.
*/
if (on && (in & PCI_CFG_GPIO_XTAL))
return 0;
if (what & XTAL)
outen |= PCI_CFG_GPIO_XTAL;
if (what & PLL)
outen |= PCI_CFG_GPIO_PLL;
if (on) {
/* turn primary xtal on */
if (what & XTAL) {
out |= PCI_CFG_GPIO_XTAL;
if (what & PLL)
out |= PCI_CFG_GPIO_PLL;
pci_write_config_dword(sii->pcibus,
PCI_GPIO_OUT, out);
pci_write_config_dword(sii->pcibus,
PCI_GPIO_OUTEN, outen);
udelay(XTAL_ON_DELAY);
}
/* turn pll on */
if (what & PLL) {
out &= ~PCI_CFG_GPIO_PLL;
pci_write_config_dword(sii->pcibus,
PCI_GPIO_OUT, out);
mdelay(2);
}
} else {
if (what & XTAL)
out &= ~PCI_CFG_GPIO_XTAL;
if (what & PLL)
out |= PCI_CFG_GPIO_PLL;
pci_write_config_dword(sii->pcibus,
PCI_GPIO_OUT, out);
pci_write_config_dword(sii->pcibus,
PCI_GPIO_OUTEN, outen);
}
return 0;
}
/* clk control mechanism through chipcommon, no policy checking */
static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
{
struct bcma_device *cc;
u32 scc;
/* chipcommon cores prior to rev6 don't support dynamic clock control */
if (ai_get_ccrev(&sii->pub) < 6)
return false;
cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
if (!(ai_get_cccaps(&sii->pub) & CC_CAP_PWR_CTL) &&
(ai_get_ccrev(&sii->pub) < 20))
return mode == CLK_FAST;
switch (mode) {
case CLK_FAST: /* FORCEHT, fast (pll) clock */
if (ai_get_ccrev(&sii->pub) < 10) {
/*
* don't forget to force xtal back
* on before we clear SCC_DYN_XTAL..
*/
ai_clkctl_xtal(&sii->pub, XTAL, ON);
bcma_maskset32(cc, CHIPCREGOFFS(slow_clk_ctl),
(SCC_XC | SCC_FS | SCC_IP), SCC_IP);
} else if (ai_get_ccrev(&sii->pub) < 20) {
bcma_set32(cc, CHIPCREGOFFS(system_clk_ctl), SYCC_HR);
} else {
bcma_set32(cc, CHIPCREGOFFS(clk_ctl_st), CCS_FORCEHT);
}
/* wait for the PLL */
if (ai_get_cccaps(&sii->pub) & CC_CAP_PMU) {
u32 htavail = CCS_HTAVAIL;
SPINWAIT(((bcma_read32(cc, CHIPCREGOFFS(clk_ctl_st)) &
htavail) == 0), PMU_MAX_TRANSITION_DLY);
} else {
udelay(PLL_DELAY);
}
break;
case CLK_DYNAMIC: /* enable dynamic clock control */
if (ai_get_ccrev(&sii->pub) < 10) {
scc = bcma_read32(cc, CHIPCREGOFFS(slow_clk_ctl));
scc &= ~(SCC_FS | SCC_IP | SCC_XC);
if ((scc & SCC_SS_MASK) != SCC_SS_XTAL)
scc |= SCC_XC;
bcma_write32(cc, CHIPCREGOFFS(slow_clk_ctl), scc);
/*
* for dynamic control, we have to
* release our xtal_pu "force on"
*/
if (scc & SCC_XC)
ai_clkctl_xtal(&sii->pub, XTAL, OFF);
} else if (ai_get_ccrev(&sii->pub) < 20) {
/* Instaclock */
bcma_mask32(cc, CHIPCREGOFFS(system_clk_ctl), ~SYCC_HR);
} else {
bcma_mask32(cc, CHIPCREGOFFS(clk_ctl_st), ~CCS_FORCEHT);
}
break;
default:
break;
}
return mode == CLK_FAST;
}
/*
* clock control policy function throught chipcommon
*
@ -1033,133 +748,53 @@ static bool _ai_clkctl_cc(struct si_info *sii, uint mode)
* this is a wrapper over the next internal function
* to allow flexible policy settings for outside caller
*/
bool ai_clkctl_cc(struct si_pub *sih, uint mode)
bool ai_clkctl_cc(struct si_pub *sih, enum bcma_clkmode mode)
{
struct si_info *sii;
struct bcma_device *cc;
sii = (struct si_info *)sih;
/* chipcommon cores prior to rev6 don't support dynamic clock control */
if (ai_get_ccrev(sih) < 6)
return false;
if (PCI_FORCEHT(sih))
return mode == CLK_FAST;
return mode == BCMA_CLKMODE_FAST;
return _ai_clkctl_cc(sii, mode);
cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
bcma_core_set_clockmode(cc, mode);
return mode == BCMA_CLKMODE_FAST;
}
void ai_pci_up(struct si_pub *sih)
{
struct si_info *sii;
struct bcma_device *cc;
sii = (struct si_info *)sih;
if (PCI_FORCEHT(sih))
_ai_clkctl_cc(sii, CLK_FAST);
if (PCI_FORCEHT(sih)) {
cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
bcma_core_set_clockmode(cc, BCMA_CLKMODE_FAST);
}
if (PCIE(sih))
pcicore_up(sii->pch, SI_PCIUP);
}
/* Unconfigure and/or apply various WARs when system is going to sleep mode */
void ai_pci_sleep(struct si_pub *sih)
{
struct si_info *sii;
sii = (struct si_info *)sih;
pcicore_sleep(sii->pch);
bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, true);
}
/* Unconfigure and/or apply various WARs when going down */
void ai_pci_down(struct si_pub *sih)
{
struct si_info *sii;
struct bcma_device *cc;
sii = (struct si_info *)sih;
/* release FORCEHT since chip is going to "down" state */
if (PCI_FORCEHT(sih))
_ai_clkctl_cc(sii, CLK_DYNAMIC);
pcicore_down(sii->pch, SI_PCIDOWN);
}
/*
* Configure the pci core for pci client (NIC) action
* coremask is the bitvec of cores by index to be enabled.
*/
void ai_pci_setup(struct si_pub *sih, uint coremask)
{
struct si_info *sii;
u32 w;
sii = (struct si_info *)sih;
/*
* Enable sb->pci interrupts. Assume
* PCI rev 2.3 support was added in pci core rev 6 and things changed..
*/
if (PCIE(sih) || (PCI(sih) && (ai_get_buscorerev(sih) >= 6))) {
/* pci config write to set this core bit in PCIIntMask */
pci_read_config_dword(sii->pcibus, PCI_INT_MASK, &w);
w |= (coremask << PCI_SBIM_SHIFT);
pci_write_config_dword(sii->pcibus, PCI_INT_MASK, w);
if (PCI_FORCEHT(sih)) {
cc = ai_findcore(&sii->pub, BCMA_CORE_CHIPCOMMON, 0);
bcma_core_set_clockmode(cc, BCMA_CLKMODE_DYNAMIC);
}
if (PCI(sih)) {
pcicore_pci_setup(sii->pch);
}
}
/*
* Fixup SROMless PCI device's configuration.
* The current core may be changed upon return.
*/
int ai_pci_fixcfg(struct si_pub *sih)
{
struct si_info *sii = (struct si_info *)sih;
/* Fixup PI in SROM shadow area to enable the correct PCI core access */
/* check 'pi' is correct and fix it if not */
pcicore_fixcfg(sii->pch);
pcicore_hwup(sii->pch);
return 0;
}
/* mask&set gpiocontrol bits */
u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val, u8 priority)
{
uint regoff;
regoff = offsetof(struct chipcregs, gpiocontrol);
return ai_cc_reg(sih, regoff, mask, val);
}
void ai_chipcontrl_epa4331(struct si_pub *sih, bool on)
{
struct bcma_device *cc;
u32 val;
cc = ai_findcore(sih, CC_CORE_ID, 0);
if (on) {
if (ai_get_chippkg(sih) == 9 || ai_get_chippkg(sih) == 0xb)
/* Ext PA Controls for 4331 12x9 Package */
bcma_set32(cc, CHIPCREGOFFS(chipcontrol),
CCTRL4331_EXTPA_EN |
CCTRL4331_EXTPA_ON_GPIO2_5);
else
/* Ext PA Controls for 4331 12x12 Package */
bcma_set32(cc, CHIPCREGOFFS(chipcontrol),
CCTRL4331_EXTPA_EN);
} else {
val &= ~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5);
bcma_mask32(cc, CHIPCREGOFFS(chipcontrol),
~(CCTRL4331_EXTPA_EN | CCTRL4331_EXTPA_ON_GPIO2_5));
}
if (PCIE(sih))
bcma_core_pci_extend_L1timer(&sii->icbus->drv_pci, false);
}
/* Enable BT-COEX & Ex-PA for 4313 */
@ -1181,6 +816,9 @@ bool ai_deviceremoved(struct si_pub *sih)
sii = (struct si_info *)sih;
if (sii->icbus->hosttype != BCMA_HOSTTYPE_PCI)
return false;
pci_read_config_dword(sii->pcibus, PCI_VENDOR_ID, &w);
if ((w & 0xFFFF) != PCI_VENDOR_ID_BROADCOM)
return true;
@ -1188,45 +826,6 @@ bool ai_deviceremoved(struct si_pub *sih)
return false;
}
bool ai_is_sprom_available(struct si_pub *sih)
{
struct si_info *sii = (struct si_info *)sih;
if (ai_get_ccrev(sih) >= 31) {
struct bcma_device *cc;
u32 sromctrl;
if ((ai_get_cccaps(sih) & CC_CAP_SROM) == 0)
return false;
cc = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0);
sromctrl = bcma_read32(cc, CHIPCREGOFFS(sromcontrol));
return sromctrl & SRC_PRESENT;
}
switch (ai_get_chip_id(sih)) {
case BCM4313_CHIP_ID:
return (sii->chipst & CST4313_SPROM_PRESENT) != 0;
default:
return true;
}
}
bool ai_is_otp_disabled(struct si_pub *sih)
{
struct si_info *sii = (struct si_info *)sih;
switch (ai_get_chip_id(sih)) {
case BCM4313_CHIP_ID:
return (sii->chipst & CST4313_OTP_PRESENT) == 0;
/* These chips always have their OTP on */
case BCM43224_CHIP_ID:
case BCM43225_CHIP_ID:
default:
return false;
}
}
uint ai_get_buscoretype(struct si_pub *sih)
{
struct si_info *sii = (struct si_info *)sih;

View File

@ -113,10 +113,6 @@
#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 */
@ -172,9 +168,7 @@ struct si_info {
struct si_pub pub; /* back plane public state (must be first) */
struct bcma_bus *icbus; /* handle to soc interconnect bus */
struct pci_dev *pcibus; /* handle to pci bus */
struct pcicore_info *pch; /* PCI/E core handle */
struct bcma_device *buscore;
struct list_head var_list; /* list of srom variables */
u32 chipst; /* chip status */
};
@ -197,38 +191,20 @@ extern u32 ai_core_cflags(struct bcma_device *core, u32 mask, u32 val);
extern struct si_pub *ai_attach(struct bcma_bus *pbus);
extern void ai_detach(struct si_pub *sih);
extern uint ai_cc_reg(struct si_pub *sih, uint regoff, u32 mask, u32 val);
extern void ai_pci_setup(struct si_pub *sih, uint coremask);
extern void ai_clkctl_init(struct si_pub *sih);
extern u16 ai_clkctl_fast_pwrup_delay(struct si_pub *sih);
extern bool ai_clkctl_cc(struct si_pub *sih, uint mode);
extern int ai_clkctl_xtal(struct si_pub *sih, uint what, bool on);
extern bool ai_deviceremoved(struct si_pub *sih);
extern u32 ai_gpiocontrol(struct si_pub *sih, u32 mask, u32 val,
u8 priority);
/* OTP status */
extern bool ai_is_otp_disabled(struct si_pub *sih);
/* SPROM availability */
extern bool ai_is_sprom_available(struct si_pub *sih);
extern void ai_pci_sleep(struct si_pub *sih);
extern void ai_pci_down(struct si_pub *sih);
extern void ai_pci_up(struct si_pub *sih);
extern int ai_pci_fixcfg(struct si_pub *sih);
extern void ai_chipcontrl_epa4331(struct si_pub *sih, bool on);
/* Enable Ex-PA for 4313 */
extern void ai_epa_4313war(struct si_pub *sih);
extern uint ai_get_buscoretype(struct si_pub *sih);
extern uint ai_get_buscorerev(struct si_pub *sih);
static inline int ai_get_ccrev(struct si_pub *sih)
{
return sih->ccrev;
}
static inline u32 ai_get_cccaps(struct si_pub *sih)
{
return sih->cccaps;

View File

@ -108,7 +108,7 @@ brcms_c_antsel_init_cfg(struct antsel_info *asi, struct brcms_antselcfg *antsel,
struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
{
struct antsel_info *asi;
struct si_pub *sih = wlc->hw->sih;
struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
asi = kzalloc(sizeof(struct antsel_info), GFP_ATOMIC);
if (!asi)
@ -118,7 +118,7 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
asi->pub = wlc->pub;
asi->antsel_type = ANTSEL_NA;
asi->antsel_avail = false;
asi->antsel_antswitch = (u8) getintvar(sih, BRCMS_SROM_ANTSWITCH);
asi->antsel_antswitch = sprom->antswitch;
if ((asi->pub->sromrev >= 4) && (asi->antsel_antswitch != 0)) {
switch (asi->antsel_antswitch) {
@ -128,12 +128,12 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
/* 4321/2 board with 2x3 switch logic */
asi->antsel_type = ANTSEL_2x3;
/* Antenna selection availability */
if (((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) ||
((u16) getintvar(sih, BRCMS_SROM_AA5G) == 7)) {
if ((sprom->ant_available_bg == 7) ||
(sprom->ant_available_a == 7)) {
asi->antsel_avail = true;
} else if (
(u16) getintvar(sih, BRCMS_SROM_AA2G) == 3 ||
(u16) getintvar(sih, BRCMS_SROM_AA5G) == 3) {
sprom->ant_available_bg == 3 ||
sprom->ant_available_a == 3) {
asi->antsel_avail = false;
} else {
asi->antsel_avail = false;
@ -146,8 +146,8 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
break;
}
} else if ((asi->pub->sromrev == 4) &&
((u16) getintvar(sih, BRCMS_SROM_AA2G) == 7) &&
((u16) getintvar(sih, BRCMS_SROM_AA5G) == 0)) {
(sprom->ant_available_bg == 7) &&
(sprom->ant_available_a == 0)) {
/* hack to match old 4321CB2 cards with 2of3 antenna switch */
asi->antsel_type = ANTSEL_2x3;
asi->antsel_avail = true;

View File

@ -1110,7 +1110,7 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
char country_abbrev[BRCM_CNTRY_BUF_SZ];
const struct country_info *country;
struct brcms_pub *pub = wlc->pub;
char *ccode;
struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
@ -1122,9 +1122,8 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
wlc->cmi = wlc_cm;
/* store the country code for passing up as a regulatory hint */
ccode = getvar(wlc->hw->sih, BRCMS_SROM_CCODE);
if (ccode && brcms_c_country_valid(ccode))
strncpy(wlc->pub->srom_ccode, ccode, BRCM_CNTRY_BUF_SZ - 1);
if (sprom->alpha2 && brcms_c_country_valid(sprom->alpha2))
strncpy(wlc->pub->srom_ccode, sprom->alpha2, sizeof(sprom->alpha2));
/*
* internal country information which must match

View File

@ -25,7 +25,6 @@
#include <linux/bcma/bcma.h>
#include <net/mac80211.h>
#include <defs.h>
#include "nicpci.h"
#include "phy/phy_int.h"
#include "d11.h"
#include "channel.h"
@ -770,7 +769,7 @@ void brcms_dpc(unsigned long data)
* Precondition: Since this function is called in brcms_pci_probe() context,
* no locking is required.
*/
static int brcms_request_fw(struct brcms_info *wl, struct pci_dev *pdev)
static int brcms_request_fw(struct brcms_info *wl, struct bcma_device *pdev)
{
int status;
struct device *device = &pdev->dev;
@ -1022,7 +1021,7 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
spin_lock_init(&wl->isr_lock);
/* prepare ucode */
if (brcms_request_fw(wl, pdev->bus->host_pci) < 0) {
if (brcms_request_fw(wl, pdev) < 0) {
wiphy_err(wl->wiphy, "%s: Failed to find firmware usually in "
"%s\n", KBUILD_MODNAME, "/lib/firmware/brcm");
brcms_release_fw(wl);
@ -1043,12 +1042,12 @@ static struct brcms_info *brcms_attach(struct bcma_device *pdev)
wl->pub->ieee_hw = hw;
/* register our interrupt handler */
if (request_irq(pdev->bus->host_pci->irq, brcms_isr,
if (request_irq(pdev->irq, brcms_isr,
IRQF_SHARED, KBUILD_MODNAME, wl)) {
wiphy_err(wl->wiphy, "wl%d: request_irq() failed\n", unit);
goto fail;
}
wl->irq = pdev->bus->host_pci->irq;
wl->irq = pdev->irq;
/* register module */
brcms_c_module_register(wl->pub, "linux", wl, NULL);
@ -1098,7 +1097,7 @@ static int __devinit brcms_bcma_probe(struct bcma_device *pdev)
dev_info(&pdev->dev, "mfg %x core %x rev %d class %d irq %d\n",
pdev->id.manuf, pdev->id.id, pdev->id.rev, pdev->id.class,
pdev->bus->host_pci->irq);
pdev->irq);
if ((pdev->id.manuf != BCMA_MANUF_BCM) ||
(pdev->id.id != BCMA_CORE_80211))

View File

@ -1219,7 +1219,7 @@ static void brcms_b_wait_for_wake(struct brcms_hardware *wlc_hw)
}
/* control chip clock to save power, enable dynamic clock or force fast clock */
static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, enum bcma_clkmode mode)
{
if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU) {
/* new chips with PMU, CCS_FORCEHT will distribute the HT clock
@ -1229,7 +1229,7 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
*/
if (wlc_hw->clk) {
if (mode == CLK_FAST) {
if (mode == BCMA_CLKMODE_FAST) {
bcma_set32(wlc_hw->d11core,
D11REGOFFS(clk_ctl_st),
CCS_FORCEHT);
@ -1260,7 +1260,7 @@ static void brcms_b_clkctl_clk(struct brcms_hardware *wlc_hw, uint mode)
~CCS_FORCEHT);
}
}
wlc_hw->forcefastclk = (mode == CLK_FAST);
wlc_hw->forcefastclk = (mode == BCMA_CLKMODE_FAST);
} else {
/* old chips w/o PMU, force HT through cc,
@ -1567,7 +1567,7 @@ void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
wlc_phy_bw_state_set(wlc_hw->band->pi, bw);
@ -1576,7 +1576,7 @@ void brcms_b_bw_set(struct brcms_hardware *wlc_hw, u16 bw)
/* restore the clk */
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
}
static void brcms_b_upd_synthpu(struct brcms_hardware *wlc_hw)
@ -1882,27 +1882,20 @@ static bool brcms_c_validboardtype(struct brcms_hardware *wlc_hw)
return true;
}
static char *brcms_c_get_macaddr(struct brcms_hardware *wlc_hw)
static void brcms_c_get_macaddr(struct brcms_hardware *wlc_hw, u8 etheraddr[ETH_ALEN])
{
enum brcms_srom_id var_id = BRCMS_SROM_MACADDR;
char *macaddr;
struct ssb_sprom *sprom = &wlc_hw->d11core->bus->sprom;
/* If macaddr exists, use it (Sromrev4, CIS, ...). */
macaddr = getvar(wlc_hw->sih, var_id);
if (macaddr != NULL)
return macaddr;
if (!is_zero_ether_addr(sprom->il0mac)) {
memcpy(etheraddr, sprom->il0mac, 6);
return;
}
if (wlc_hw->_nbands > 1)
var_id = BRCMS_SROM_ET1MACADDR;
memcpy(etheraddr, sprom->et1mac, 6);
else
var_id = BRCMS_SROM_IL0MACADDR;
macaddr = getvar(wlc_hw->sih, var_id);
if (macaddr == NULL)
wiphy_err(wlc_hw->wlc->wiphy, "wl%d: wlc_get_macaddr: macaddr "
"getvar(%d) not found\n", wlc_hw->unit, var_id);
return macaddr;
memcpy(etheraddr, sprom->il0mac, 6);
}
/* power both the pll and external oscillator on/off */
@ -1917,9 +1910,6 @@ static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
if (!want && wlc_hw->pllreq)
return;
if (wlc_hw->sih)
ai_clkctl_xtal(wlc_hw->sih, XTAL | PLL, want);
wlc_hw->sbclk = want;
if (!wlc_hw->sbclk) {
wlc_hw->clk = false;
@ -2004,7 +1994,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/* reset the dma engines except first time thru */
if (bcma_core_is_enabled(wlc_hw->d11core)) {
@ -2053,7 +2043,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
brcms_c_mctrl_reset(wlc_hw);
if (ai_get_cccaps(wlc_hw->sih) & CC_CAP_PMU)
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
brcms_b_phy_reset(wlc_hw);
@ -2065,7 +2055,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
/* restore the clk setting */
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
}
/* txfifo sizes needs to be modified(increased) since the newer cores
@ -2218,7 +2208,7 @@ static void brcms_c_gpio_init(struct brcms_c_info *wlc)
gm |= gc |= BOARD_GPIO_PACTRL;
/* apply to gpiocontrol register */
ai_gpiocontrol(wlc_hw->sih, gm, gc, GPIO_DRV_PRIORITY);
bcma_chipco_gpio_control(&wlc_hw->d11core->bus->drv_cc, gm, gc);
}
static void brcms_ucode_write(struct brcms_hardware *wlc_hw,
@ -3371,7 +3361,7 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
/* request FAST clock if not on */
fastclk = wlc_hw->forcefastclk;
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/* disable interrupts */
macintmask = brcms_intrsoff(wlc->wl);
@ -3405,7 +3395,7 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
/* restore the clk */
if (!fastclk)
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
}
static void brcms_c_set_phy_chanspec(struct brcms_c_info *wlc,
@ -4436,17 +4426,22 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
uint unit, bool piomode)
{
struct brcms_hardware *wlc_hw;
char *macaddr = NULL;
uint err = 0;
uint j;
bool wme = false;
struct shared_phy_params sha_params;
struct wiphy *wiphy = wlc->wiphy;
struct pci_dev *pcidev = core->bus->host_pci;
struct ssb_sprom *sprom = &core->bus->sprom;
BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
pcidev->vendor,
pcidev->device);
if (core->bus->hosttype == BCMA_HOSTTYPE_PCI)
BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
pcidev->vendor,
pcidev->device);
else
BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
core->bus->boardinfo.vendor,
core->bus->boardinfo.type);
wme = true;
@ -4472,7 +4467,8 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
}
/* verify again the device is supported */
if (!brcms_c_chipmatch(pcidev->vendor, pcidev->device)) {
if (core->bus->hosttype == BCMA_HOSTTYPE_PCI &&
!brcms_c_chipmatch(pcidev->vendor, pcidev->device)) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: Unsupported "
"vendor/device (0x%x/0x%x)\n",
unit, pcidev->vendor, pcidev->device);
@ -4480,8 +4476,13 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
goto fail;
}
wlc_hw->vendorid = pcidev->vendor;
wlc_hw->deviceid = pcidev->device;
if (core->bus->hosttype == BCMA_HOSTTYPE_PCI) {
wlc_hw->vendorid = pcidev->vendor;
wlc_hw->deviceid = pcidev->device;
} else {
wlc_hw->vendorid = core->bus->boardinfo.vendor;
wlc_hw->deviceid = core->bus->boardinfo.type;
}
wlc_hw->d11core = core;
wlc_hw->corerev = core->id.rev;
@ -4501,7 +4502,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
* is still false; But it will be called again inside wlc_corereset,
* after d11 is out of reset.
*/
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
if (!brcms_b_validate_chip_access(wlc_hw)) {
@ -4512,7 +4513,7 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
}
/* get the board rev, used just below */
j = getintvar(wlc_hw->sih, BRCMS_SROM_BOARDREV);
j = sprom->board_rev;
/* promote srom boardrev of 0xFF to 1 */
if (j == BOARDREV_PROMOTABLE)
j = BOARDREV_PROMOTED;
@ -4525,11 +4526,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
err = 15;
goto fail;
}
wlc_hw->sromrev = (u8) getintvar(wlc_hw->sih, BRCMS_SROM_REV);
wlc_hw->boardflags = (u32) getintvar(wlc_hw->sih,
BRCMS_SROM_BOARDFLAGS);
wlc_hw->boardflags2 = (u32) getintvar(wlc_hw->sih,
BRCMS_SROM_BOARDFLAGS2);
wlc_hw->sromrev = sprom->revision;
wlc_hw->boardflags = sprom->boardflags_lo + (sprom->boardflags_hi << 16);
wlc_hw->boardflags2 = sprom->boardflags2_lo + (sprom->boardflags2_hi << 16);
if (wlc_hw->boardflags & BFL_NOPLLDOWN)
brcms_b_pllreq(wlc_hw, true, BRCMS_PLLREQ_SHARED);
@ -4702,25 +4701,18 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
*/
/* init etheraddr state variables */
macaddr = brcms_c_get_macaddr(wlc_hw);
if (macaddr == NULL) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: macaddr not found\n",
unit);
err = 21;
goto fail;
}
if (!mac_pton(macaddr, wlc_hw->etheraddr) ||
is_broadcast_ether_addr(wlc_hw->etheraddr) ||
brcms_c_get_macaddr(wlc_hw, wlc_hw->etheraddr);
if (is_broadcast_ether_addr(wlc_hw->etheraddr) ||
is_zero_ether_addr(wlc_hw->etheraddr)) {
wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr %s\n",
unit, macaddr);
wiphy_err(wiphy, "wl%d: brcms_b_attach: bad macaddr\n",
unit);
err = 22;
goto fail;
}
BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x macaddr: %s\n",
wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih),
macaddr);
BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x\n",
wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih));
return err;
@ -4770,16 +4762,16 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
int aa;
uint unit;
int bandtype;
struct si_pub *sih = wlc->hw->sih;
struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
unit = wlc->pub->unit;
bandtype = wlc->band->bandtype;
/* get antennas available */
if (bandtype == BRCM_BAND_5G)
aa = (s8) getintvar(sih, BRCMS_SROM_AA5G);
aa = sprom->ant_available_a;
else
aa = (s8) getintvar(sih, BRCMS_SROM_AA2G);
aa = sprom->ant_available_bg;
if ((aa < 1) || (aa > 15)) {
wiphy_err(wlc->wiphy, "wl%d: %s: Invalid antennas available in"
@ -4799,9 +4791,9 @@ static bool brcms_c_attach_stf_ant_init(struct brcms_c_info *wlc)
/* Compute Antenna Gain */
if (bandtype == BRCM_BAND_5G)
wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG1);
wlc->band->antgain = sprom->antenna_gain.a1;
else
wlc->band->antgain = (s8) getintvar(sih, BRCMS_SROM_AG0);
wlc->band->antgain = sprom->antenna_gain.a0;
brcms_c_attach_antgain_init(wlc);
@ -4952,15 +4944,6 @@ static int brcms_b_detach(struct brcms_c_info *wlc)
callbacks = 0;
if (wlc_hw->sih) {
/*
* detach interrupt sync mechanism since interrupt is disabled
* and per-port interrupt object may has been freed. this must
* be done before sb core switch
*/
ai_pci_sleep(wlc_hw->sih);
}
brcms_b_detach_dmapio(wlc_hw);
band = wlc_hw->band;
@ -5047,9 +5030,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
*/
brcms_b_xtal(wlc_hw, ON);
ai_clkctl_init(wlc_hw->sih);
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
ai_pci_fixcfg(wlc_hw->sih);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/*
* TODO: test suspend/resume
@ -5078,8 +5059,6 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
{
uint coremask;
BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
/*
@ -5088,15 +5067,14 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
*/
brcms_b_xtal(wlc_hw, ON);
ai_clkctl_init(wlc_hw->sih);
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
/*
* Configure pci/pcmcia here instead of in brcms_c_attach()
* to allow mfg hotswap: down, hotswap (chip power cycle), up.
*/
coremask = (1 << wlc_hw->wlc->core->coreidx);
ai_pci_setup(wlc_hw->sih, coremask);
bcma_core_pci_irq_ctl(&wlc_hw->d11core->bus->drv_pci, wlc_hw->d11core,
true);
/*
* Need to read the hwradio status here to cover the case where the
@ -5126,7 +5104,7 @@ static int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
/* FULLY enable dynamic power control and d11 core interrupt */
brcms_b_clkctl_clk(wlc_hw, CLK_DYNAMIC);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_DYNAMIC);
brcms_intrson(wlc_hw->wlc->wl);
return 0;
}
@ -5267,7 +5245,7 @@ static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
brcms_intrsoff(wlc_hw->wlc->wl);
/* ensure we're running on the pll clock again */
brcms_b_clkctl_clk(wlc_hw, CLK_FAST);
brcms_b_clkctl_clk(wlc_hw, BCMA_CLKMODE_FAST);
}
/* down phy at the last of this stage */
callbacks += wlc_phy_down(wlc_hw->band->pi);

View File

@ -1,826 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/slab.h>
#include <linux/delay.h>
#include <linux/pci.h>
#include <defs.h>
#include <soc.h>
#include <chipcommon.h>
#include "aiutils.h"
#include "pub.h"
#include "nicpci.h"
/* SPROM offsets */
#define SRSH_ASPM_OFFSET 4 /* word 4 */
#define SRSH_ASPM_ENB 0x18 /* bit 3, 4 */
#define SRSH_ASPM_L1_ENB 0x10 /* bit 4 */
#define SRSH_ASPM_L0s_ENB 0x8 /* bit 3 */
#define SRSH_PCIE_MISC_CONFIG 5 /* word 5 */
#define SRSH_L23READY_EXIT_NOPERST 0x8000 /* bit 15 */
#define SRSH_CLKREQ_OFFSET_REV5 20 /* word 20 for srom rev <= 5 */
#define SRSH_CLKREQ_ENB 0x0800 /* bit 11 */
#define SRSH_BD_OFFSET 6 /* word 6 */
/* chipcontrol */
#define CHIPCTRL_4321_PLL_DOWN 0x800000/* serdes PLL down override */
/* MDIO control */
#define MDIOCTL_DIVISOR_MASK 0x7f /* clock to be used on MDIO */
#define MDIOCTL_DIVISOR_VAL 0x2
#define MDIOCTL_PREAM_EN 0x80 /* Enable preamble sequnce */
#define MDIOCTL_ACCESS_DONE 0x100 /* Transaction complete */
/* MDIO Data */
#define MDIODATA_MASK 0x0000ffff /* data 2 bytes */
#define MDIODATA_TA 0x00020000 /* Turnaround */
#define MDIODATA_REGADDR_SHF 18 /* Regaddr shift */
#define MDIODATA_REGADDR_MASK 0x007c0000 /* Regaddr Mask */
#define MDIODATA_DEVADDR_SHF 23 /* Physmedia devaddr shift */
#define MDIODATA_DEVADDR_MASK 0x0f800000
/* Physmedia devaddr Mask */
/* MDIO Data for older revisions < 10 */
#define MDIODATA_REGADDR_SHF_OLD 18 /* Regaddr shift */
#define MDIODATA_REGADDR_MASK_OLD 0x003c0000
/* Regaddr Mask */
#define MDIODATA_DEVADDR_SHF_OLD 22 /* Physmedia devaddr shift */
#define MDIODATA_DEVADDR_MASK_OLD 0x0fc00000
/* Physmedia devaddr Mask */
/* Transactions flags */
#define MDIODATA_WRITE 0x10000000
#define MDIODATA_READ 0x20000000
#define MDIODATA_START 0x40000000
#define MDIODATA_DEV_ADDR 0x0 /* dev address for serdes */
#define MDIODATA_BLK_ADDR 0x1F /* blk address for serdes */
/* serdes regs (rev < 10) */
#define MDIODATA_DEV_PLL 0x1d /* SERDES PLL Dev */
#define MDIODATA_DEV_TX 0x1e /* SERDES TX Dev */
#define MDIODATA_DEV_RX 0x1f /* SERDES RX Dev */
/* SERDES RX registers */
#define SERDES_RX_CTRL 1 /* Rx cntrl */
#define SERDES_RX_TIMER1 2 /* Rx Timer1 */
#define SERDES_RX_CDR 6 /* CDR */
#define SERDES_RX_CDRBW 7 /* CDR BW */
/* SERDES RX control register */
#define SERDES_RX_CTRL_FORCE 0x80 /* rxpolarity_force */
#define SERDES_RX_CTRL_POLARITY 0x40 /* rxpolarity_value */
/* SERDES PLL registers */
#define SERDES_PLL_CTRL 1 /* PLL control reg */
#define PLL_CTRL_FREQDET_EN 0x4000 /* bit 14 is FREQDET on */
/* Linkcontrol reg offset in PCIE Cap */
#define PCIE_CAP_LINKCTRL_OFFSET 16 /* offset in pcie cap */
#define PCIE_CAP_LCREG_ASPML0s 0x01 /* ASPM L0s in linkctrl */
#define PCIE_CAP_LCREG_ASPML1 0x02 /* ASPM L1 in linkctrl */
#define PCIE_CLKREQ_ENAB 0x100 /* CLKREQ Enab in linkctrl */
#define PCIE_ASPM_ENAB 3 /* ASPM L0s & L1 in linkctrl */
#define PCIE_ASPM_L1_ENAB 2 /* ASPM L0s & L1 in linkctrl */
#define PCIE_ASPM_L0s_ENAB 1 /* ASPM L0s & L1 in linkctrl */
#define PCIE_ASPM_DISAB 0 /* ASPM L0s & L1 in linkctrl */
/* Power management threshold */
#define PCIE_L1THRESHOLDTIME_MASK 0xFF00 /* bits 8 - 15 */
#define PCIE_L1THRESHOLDTIME_SHIFT 8 /* PCIE_L1THRESHOLDTIME_SHIFT */
#define PCIE_L1THRESHOLD_WARVAL 0x72 /* WAR value */
#define PCIE_ASPMTIMER_EXTEND 0x01000000
/* > rev7:
* enable extend ASPM timer
*/
/* different register spaces to access thru pcie indirect access */
#define PCIE_CONFIGREGS 1 /* Access to config space */
#define PCIE_PCIEREGS 2 /* Access to pcie registers */
/* PCIE protocol PHY diagnostic registers */
#define PCIE_PLP_STATUSREG 0x204 /* Status */
/* Status reg PCIE_PLP_STATUSREG */
#define PCIE_PLP_POLARITYINV_STAT 0x10
/* PCIE protocol DLLP diagnostic registers */
#define PCIE_DLLP_LCREG 0x100 /* Link Control */
#define PCIE_DLLP_PMTHRESHREG 0x128 /* Power Management Threshold */
/* PCIE protocol TLP diagnostic registers */
#define PCIE_TLP_WORKAROUNDSREG 0x004 /* TLP Workarounds */
/* Sonics to PCI translation types */
#define SBTOPCI_PREF 0x4 /* prefetch enable */
#define SBTOPCI_BURST 0x8 /* burst enable */
#define SBTOPCI_RC_READMULTI 0x20 /* memory read multiple */
#define PCI_CLKRUN_DSBL 0x8000 /* Bit 15 forceClkrun */
/* PCI core index in SROM shadow area */
#define SRSH_PI_OFFSET 0 /* first word */
#define SRSH_PI_MASK 0xf000 /* bit 15:12 */
#define SRSH_PI_SHIFT 12 /* bit 15:12 */
#define PCIREGOFFS(field) offsetof(struct sbpciregs, field)
#define PCIEREGOFFS(field) offsetof(struct sbpcieregs, field)
/* Sonics side: PCI core and host control registers */
struct sbpciregs {
u32 control; /* PCI control */
u32 PAD[3];
u32 arbcontrol; /* PCI arbiter control */
u32 clkrun; /* Clkrun Control (>=rev11) */
u32 PAD[2];
u32 intstatus; /* Interrupt status */
u32 intmask; /* Interrupt mask */
u32 sbtopcimailbox; /* Sonics to PCI mailbox */
u32 PAD[9];
u32 bcastaddr; /* Sonics broadcast address */
u32 bcastdata; /* Sonics broadcast data */
u32 PAD[2];
u32 gpioin; /* ro: gpio input (>=rev2) */
u32 gpioout; /* rw: gpio output (>=rev2) */
u32 gpioouten; /* rw: gpio output enable (>= rev2) */
u32 gpiocontrol; /* rw: gpio control (>= rev2) */
u32 PAD[36];
u32 sbtopci0; /* Sonics to PCI translation 0 */
u32 sbtopci1; /* Sonics to PCI translation 1 */
u32 sbtopci2; /* Sonics to PCI translation 2 */
u32 PAD[189];
u32 pcicfg[4][64]; /* 0x400 - 0x7FF, PCI Cfg Space (>=rev8) */
u16 sprom[36]; /* SPROM shadow Area */
u32 PAD[46];
};
/* SB side: PCIE core and host control registers */
struct sbpcieregs {
u32 control; /* host mode only */
u32 PAD[2];
u32 biststatus; /* bist Status: 0x00C */
u32 gpiosel; /* PCIE gpio sel: 0x010 */
u32 gpioouten; /* PCIE gpio outen: 0x14 */
u32 PAD[2];
u32 intstatus; /* Interrupt status: 0x20 */
u32 intmask; /* Interrupt mask: 0x24 */
u32 sbtopcimailbox; /* sb to pcie mailbox: 0x028 */
u32 PAD[53];
u32 sbtopcie0; /* sb to pcie translation 0: 0x100 */
u32 sbtopcie1; /* sb to pcie translation 1: 0x104 */
u32 sbtopcie2; /* sb to pcie translation 2: 0x108 */
u32 PAD[5];
/* pcie core supports in direct access to config space */
u32 configaddr; /* pcie config space access: Address field: 0x120 */
u32 configdata; /* pcie config space access: Data field: 0x124 */
/* mdio access to serdes */
u32 mdiocontrol; /* controls the mdio access: 0x128 */
u32 mdiodata; /* Data to the mdio access: 0x12c */
/* pcie protocol phy/dllp/tlp register indirect access mechanism */
u32 pcieindaddr; /* indirect access to
* the internal register: 0x130
*/
u32 pcieinddata; /* Data to/from the internal regsiter: 0x134 */
u32 clkreqenctrl; /* >= rev 6, Clkreq rdma control : 0x138 */
u32 PAD[177];
u32 pciecfg[4][64]; /* 0x400 - 0x7FF, PCIE Cfg Space */
u16 sprom[64]; /* SPROM shadow Area */
};
struct pcicore_info {
struct bcma_device *core;
struct si_pub *sih; /* System interconnect handle */
struct pci_dev *dev;
u8 pciecap_lcreg_offset;/* PCIE capability LCreg offset
* in the config space
*/
bool pcie_pr42767;
u8 pcie_polarity;
u8 pcie_war_aspm_ovr; /* Override ASPM/Clkreq settings */
u8 pmecap_offset; /* PM Capability offset in the config space */
bool pmecap; /* Capable of generating PME */
};
#define PCIE_ASPM(sih) \
((ai_get_buscoretype(sih) == PCIE_CORE_ID) && \
((ai_get_buscorerev(sih) >= 3) && \
(ai_get_buscorerev(sih) <= 5)))
/* delay needed between the mdio control/ mdiodata register data access */
static void pr28829_delay(void)
{
udelay(10);
}
/* Initialize the PCI core.
* It's caller's responsibility to make sure that this is done only once
*/
struct pcicore_info *pcicore_init(struct si_pub *sih, struct bcma_device *core)
{
struct pcicore_info *pi;
/* alloc struct pcicore_info */
pi = kzalloc(sizeof(struct pcicore_info), GFP_ATOMIC);
if (pi == NULL)
return NULL;
pi->sih = sih;
pi->dev = core->bus->host_pci;
pi->core = core;
if (core->id.id == PCIE_CORE_ID) {
u8 cap_ptr;
cap_ptr = pcicore_find_pci_capability(pi->dev, PCI_CAP_ID_EXP,
NULL, NULL);
pi->pciecap_lcreg_offset = cap_ptr + PCIE_CAP_LINKCTRL_OFFSET;
}
return pi;
}
void pcicore_deinit(struct pcicore_info *pch)
{
kfree(pch);
}
/* return cap_offset if requested capability exists in the PCI config space */
/* Note that it's caller's responsibility to make sure it's a pci bus */
u8
pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id,
unsigned char *buf, u32 *buflen)
{
u8 cap_id;
u8 cap_ptr = 0;
u32 bufsize;
u8 byte_val;
/* check for Header type 0 */
pci_read_config_byte(dev, PCI_HEADER_TYPE, &byte_val);
if ((byte_val & 0x7f) != PCI_HEADER_TYPE_NORMAL)
goto end;
/* check if the capability pointer field exists */
pci_read_config_byte(dev, PCI_STATUS, &byte_val);
if (!(byte_val & PCI_STATUS_CAP_LIST))
goto end;
pci_read_config_byte(dev, PCI_CAPABILITY_LIST, &cap_ptr);
/* check if the capability pointer is 0x00 */
if (cap_ptr == 0x00)
goto end;
/* loop thru the capability list
* and see if the pcie capability exists
*/
pci_read_config_byte(dev, cap_ptr, &cap_id);
while (cap_id != req_cap_id) {
pci_read_config_byte(dev, cap_ptr + 1, &cap_ptr);
if (cap_ptr == 0x00)
break;
pci_read_config_byte(dev, cap_ptr, &cap_id);
}
if (cap_id != req_cap_id)
goto end;
/* found the caller requested capability */
if (buf != NULL && buflen != NULL) {
u8 cap_data;
bufsize = *buflen;
if (!bufsize)
goto end;
*buflen = 0;
/* copy the capability data excluding cap ID and next ptr */
cap_data = cap_ptr + 2;
if ((bufsize + cap_data) > PCI_SZPCR)
bufsize = PCI_SZPCR - cap_data;
*buflen = bufsize;
while (bufsize--) {
pci_read_config_byte(dev, cap_data, buf);
cap_data++;
buf++;
}
}
end:
return cap_ptr;
}
/* ***** Register Access API */
static uint
pcie_readreg(struct bcma_device *core, uint addrtype, uint offset)
{
uint retval = 0xFFFFFFFF;
switch (addrtype) {
case PCIE_CONFIGREGS:
bcma_write32(core, PCIEREGOFFS(configaddr), offset);
(void)bcma_read32(core, PCIEREGOFFS(configaddr));
retval = bcma_read32(core, PCIEREGOFFS(configdata));
break;
case PCIE_PCIEREGS:
bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset);
(void)bcma_read32(core, PCIEREGOFFS(pcieindaddr));
retval = bcma_read32(core, PCIEREGOFFS(pcieinddata));
break;
}
return retval;
}
static uint pcie_writereg(struct bcma_device *core, uint addrtype,
uint offset, uint val)
{
switch (addrtype) {
case PCIE_CONFIGREGS:
bcma_write32(core, PCIEREGOFFS(configaddr), offset);
bcma_write32(core, PCIEREGOFFS(configdata), val);
break;
case PCIE_PCIEREGS:
bcma_write32(core, PCIEREGOFFS(pcieindaddr), offset);
bcma_write32(core, PCIEREGOFFS(pcieinddata), val);
break;
default:
break;
}
return 0;
}
static bool pcie_mdiosetblock(struct pcicore_info *pi, uint blk)
{
uint mdiodata, i = 0;
uint pcie_serdes_spinwait = 200;
mdiodata = (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA |
(MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
(MDIODATA_BLK_ADDR << MDIODATA_REGADDR_SHF) |
(blk << 4));
bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata);
pr28829_delay();
/* retry till the transaction is complete */
while (i < pcie_serdes_spinwait) {
if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) &
MDIOCTL_ACCESS_DONE)
break;
udelay(1000);
i++;
}
if (i >= pcie_serdes_spinwait)
return false;
return true;
}
static int
pcie_mdioop(struct pcicore_info *pi, uint physmedia, uint regaddr, bool write,
uint *val)
{
uint mdiodata;
uint i = 0;
uint pcie_serdes_spinwait = 10;
/* enable mdio access to SERDES */
bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol),
MDIOCTL_PREAM_EN | MDIOCTL_DIVISOR_VAL);
if (ai_get_buscorerev(pi->sih) >= 10) {
/* new serdes is slower in rw,
* using two layers of reg address mapping
*/
if (!pcie_mdiosetblock(pi, physmedia))
return 1;
mdiodata = ((MDIODATA_DEV_ADDR << MDIODATA_DEVADDR_SHF) |
(regaddr << MDIODATA_REGADDR_SHF));
pcie_serdes_spinwait *= 20;
} else {
mdiodata = ((physmedia << MDIODATA_DEVADDR_SHF_OLD) |
(regaddr << MDIODATA_REGADDR_SHF_OLD));
}
if (!write)
mdiodata |= (MDIODATA_START | MDIODATA_READ | MDIODATA_TA);
else
mdiodata |= (MDIODATA_START | MDIODATA_WRITE | MDIODATA_TA |
*val);
bcma_write32(pi->core, PCIEREGOFFS(mdiodata), mdiodata);
pr28829_delay();
/* retry till the transaction is complete */
while (i < pcie_serdes_spinwait) {
if (bcma_read32(pi->core, PCIEREGOFFS(mdiocontrol)) &
MDIOCTL_ACCESS_DONE) {
if (!write) {
pr28829_delay();
*val = (bcma_read32(pi->core,
PCIEREGOFFS(mdiodata)) &
MDIODATA_MASK);
}
/* Disable mdio access to SERDES */
bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0);
return 0;
}
udelay(1000);
i++;
}
/* Timed out. Disable mdio access to SERDES. */
bcma_write32(pi->core, PCIEREGOFFS(mdiocontrol), 0);
return 1;
}
/* use the mdio interface to read from mdio slaves */
static int
pcie_mdioread(struct pcicore_info *pi, uint physmedia, uint regaddr,
uint *regval)
{
return pcie_mdioop(pi, physmedia, regaddr, false, regval);
}
/* use the mdio interface to write to mdio slaves */
static int
pcie_mdiowrite(struct pcicore_info *pi, uint physmedia, uint regaddr, uint val)
{
return pcie_mdioop(pi, physmedia, regaddr, true, &val);
}
/* ***** Support functions ***** */
static u8 pcie_clkreq(struct pcicore_info *pi, u32 mask, u32 val)
{
u32 reg_val;
u8 offset;
offset = pi->pciecap_lcreg_offset;
if (!offset)
return 0;
pci_read_config_dword(pi->dev, offset, &reg_val);
/* set operation */
if (mask) {
if (val)
reg_val |= PCIE_CLKREQ_ENAB;
else
reg_val &= ~PCIE_CLKREQ_ENAB;
pci_write_config_dword(pi->dev, offset, reg_val);
pci_read_config_dword(pi->dev, offset, &reg_val);
}
if (reg_val & PCIE_CLKREQ_ENAB)
return 1;
else
return 0;
}
static void pcie_extendL1timer(struct pcicore_info *pi, bool extend)
{
u32 w;
struct si_pub *sih = pi->sih;
if (ai_get_buscoretype(sih) != PCIE_CORE_ID ||
ai_get_buscorerev(sih) < 7)
return;
w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
if (extend)
w |= PCIE_ASPMTIMER_EXTEND;
else
w &= ~PCIE_ASPMTIMER_EXTEND;
pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG, w);
w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_PMTHRESHREG);
}
/* centralized clkreq control policy */
static void pcie_clkreq_upd(struct pcicore_info *pi, uint state)
{
struct si_pub *sih = pi->sih;
switch (state) {
case SI_DOATTACH:
if (PCIE_ASPM(sih))
pcie_clkreq(pi, 1, 0);
break;
case SI_PCIDOWN:
/* turn on serdes PLL down */
if (ai_get_buscorerev(sih) == 6) {
ai_cc_reg(sih,
offsetof(struct chipcregs, chipcontrol_addr),
~0, 0);
ai_cc_reg(sih,
offsetof(struct chipcregs, chipcontrol_data),
~0x40, 0);
} else if (pi->pcie_pr42767) {
pcie_clkreq(pi, 1, 1);
}
break;
case SI_PCIUP:
/* turn off serdes PLL down */
if (ai_get_buscorerev(sih) == 6) {
ai_cc_reg(sih,
offsetof(struct chipcregs, chipcontrol_addr),
~0, 0);
ai_cc_reg(sih,
offsetof(struct chipcregs, chipcontrol_data),
~0x40, 0x40);
} else if (PCIE_ASPM(sih)) { /* disable clkreq */
pcie_clkreq(pi, 1, 0);
}
break;
}
}
/* ***** PCI core WARs ***** */
/* Done only once at attach time */
static void pcie_war_polarity(struct pcicore_info *pi)
{
u32 w;
if (pi->pcie_polarity != 0)
return;
w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_PLP_STATUSREG);
/* Detect the current polarity at attach and force that polarity and
* disable changing the polarity
*/
if ((w & PCIE_PLP_POLARITYINV_STAT) == 0)
pi->pcie_polarity = SERDES_RX_CTRL_FORCE;
else
pi->pcie_polarity = (SERDES_RX_CTRL_FORCE |
SERDES_RX_CTRL_POLARITY);
}
/* enable ASPM and CLKREQ if srom doesn't have it */
/* Needs to happen when update to shadow SROM is needed
* : Coming out of 'standby'/'hibernate'
* : If pcie_war_aspm_ovr state changed
*/
static void pcie_war_aspm_clkreq(struct pcicore_info *pi)
{
struct si_pub *sih = pi->sih;
u16 val16;
u32 w;
if (!PCIE_ASPM(sih))
return;
/* bypass this on QT or VSIM */
val16 = bcma_read16(pi->core, PCIEREGOFFS(sprom[SRSH_ASPM_OFFSET]));
val16 &= ~SRSH_ASPM_ENB;
if (pi->pcie_war_aspm_ovr == PCIE_ASPM_ENAB)
val16 |= SRSH_ASPM_ENB;
else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L1_ENAB)
val16 |= SRSH_ASPM_L1_ENB;
else if (pi->pcie_war_aspm_ovr == PCIE_ASPM_L0s_ENAB)
val16 |= SRSH_ASPM_L0s_ENB;
bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_ASPM_OFFSET]), val16);
pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w);
w &= ~PCIE_ASPM_ENAB;
w |= pi->pcie_war_aspm_ovr;
pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w);
val16 = bcma_read16(pi->core,
PCIEREGOFFS(sprom[SRSH_CLKREQ_OFFSET_REV5]));
if (pi->pcie_war_aspm_ovr != PCIE_ASPM_DISAB) {
val16 |= SRSH_CLKREQ_ENB;
pi->pcie_pr42767 = true;
} else
val16 &= ~SRSH_CLKREQ_ENB;
bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_CLKREQ_OFFSET_REV5]),
val16);
}
/* Apply the polarity determined at the start */
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void pcie_war_serdes(struct pcicore_info *pi)
{
u32 w = 0;
if (pi->pcie_polarity != 0)
pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CTRL,
pi->pcie_polarity);
pcie_mdioread(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, &w);
if (w & PLL_CTRL_FREQDET_EN) {
w &= ~PLL_CTRL_FREQDET_EN;
pcie_mdiowrite(pi, MDIODATA_DEV_PLL, SERDES_PLL_CTRL, w);
}
}
/* Fix MISC config to allow coming out of L2/L3-Ready state w/o PRST */
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void pcie_misc_config_fixup(struct pcicore_info *pi)
{
u16 val16;
val16 = bcma_read16(pi->core,
PCIEREGOFFS(sprom[SRSH_PCIE_MISC_CONFIG]));
if ((val16 & SRSH_L23READY_EXIT_NOPERST) == 0) {
val16 |= SRSH_L23READY_EXIT_NOPERST;
bcma_write16(pi->core,
PCIEREGOFFS(sprom[SRSH_PCIE_MISC_CONFIG]), val16);
}
}
/* quick hack for testing */
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void pcie_war_noplldown(struct pcicore_info *pi)
{
/* turn off serdes PLL down */
ai_cc_reg(pi->sih, offsetof(struct chipcregs, chipcontrol),
CHIPCTRL_4321_PLL_DOWN, CHIPCTRL_4321_PLL_DOWN);
/* clear srom shadow backdoor */
bcma_write16(pi->core, PCIEREGOFFS(sprom[SRSH_BD_OFFSET]), 0);
}
/* Needs to happen when coming out of 'standby'/'hibernate' */
static void pcie_war_pci_setup(struct pcicore_info *pi)
{
struct si_pub *sih = pi->sih;
u32 w;
if (ai_get_buscorerev(sih) == 0 || ai_get_buscorerev(sih) == 1) {
w = pcie_readreg(pi->core, PCIE_PCIEREGS,
PCIE_TLP_WORKAROUNDSREG);
w |= 0x8;
pcie_writereg(pi->core, PCIE_PCIEREGS,
PCIE_TLP_WORKAROUNDSREG, w);
}
if (ai_get_buscorerev(sih) == 1) {
w = pcie_readreg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_LCREG);
w |= 0x40;
pcie_writereg(pi->core, PCIE_PCIEREGS, PCIE_DLLP_LCREG, w);
}
if (ai_get_buscorerev(sih) == 0) {
pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_TIMER1, 0x8128);
pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDR, 0x0100);
pcie_mdiowrite(pi, MDIODATA_DEV_RX, SERDES_RX_CDRBW, 0x1466);
} else if (PCIE_ASPM(sih)) {
/* Change the L1 threshold for better performance */
w = pcie_readreg(pi->core, PCIE_PCIEREGS,
PCIE_DLLP_PMTHRESHREG);
w &= ~PCIE_L1THRESHOLDTIME_MASK;
w |= PCIE_L1THRESHOLD_WARVAL << PCIE_L1THRESHOLDTIME_SHIFT;
pcie_writereg(pi->core, PCIE_PCIEREGS,
PCIE_DLLP_PMTHRESHREG, w);
pcie_war_serdes(pi);
pcie_war_aspm_clkreq(pi);
} else if (ai_get_buscorerev(pi->sih) == 7)
pcie_war_noplldown(pi);
/* Note that the fix is actually in the SROM,
* that's why this is open-ended
*/
if (ai_get_buscorerev(pi->sih) >= 6)
pcie_misc_config_fixup(pi);
}
/* ***** Functions called during driver state changes ***** */
void pcicore_attach(struct pcicore_info *pi, int state)
{
struct si_pub *sih = pi->sih;
u32 bfl2 = (u32)getintvar(sih, BRCMS_SROM_BOARDFLAGS2);
/* Determine if this board needs override */
if (PCIE_ASPM(sih)) {
if (bfl2 & BFL2_PCIEWAR_OVR)
pi->pcie_war_aspm_ovr = PCIE_ASPM_DISAB;
else
pi->pcie_war_aspm_ovr = PCIE_ASPM_ENAB;
}
/* These need to happen in this order only */
pcie_war_polarity(pi);
pcie_war_serdes(pi);
pcie_war_aspm_clkreq(pi);
pcie_clkreq_upd(pi, state);
}
void pcicore_hwup(struct pcicore_info *pi)
{
if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID)
return;
pcie_war_pci_setup(pi);
}
void pcicore_up(struct pcicore_info *pi, int state)
{
if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID)
return;
/* Restore L1 timer for better performance */
pcie_extendL1timer(pi, true);
pcie_clkreq_upd(pi, state);
}
/* When the device is going to enter D3 state
* (or the system is going to enter S3/S4 states)
*/
void pcicore_sleep(struct pcicore_info *pi)
{
u32 w;
if (!pi || !PCIE_ASPM(pi->sih))
return;
pci_read_config_dword(pi->dev, pi->pciecap_lcreg_offset, &w);
w &= ~PCIE_CAP_LCREG_ASPML1;
pci_write_config_dword(pi->dev, pi->pciecap_lcreg_offset, w);
pi->pcie_pr42767 = false;
}
void pcicore_down(struct pcicore_info *pi, int state)
{
if (!pi || ai_get_buscoretype(pi->sih) != PCIE_CORE_ID)
return;
pcie_clkreq_upd(pi, state);
/* Reduce L1 timer for better power savings */
pcie_extendL1timer(pi, false);
}
void pcicore_fixcfg(struct pcicore_info *pi)
{
struct bcma_device *core = pi->core;
u16 val16;
uint regoff;
switch (pi->core->id.id) {
case BCMA_CORE_PCI:
regoff = PCIREGOFFS(sprom[SRSH_PI_OFFSET]);
break;
case BCMA_CORE_PCIE:
regoff = PCIEREGOFFS(sprom[SRSH_PI_OFFSET]);
break;
default:
return;
}
val16 = bcma_read16(pi->core, regoff);
if (((val16 & SRSH_PI_MASK) >> SRSH_PI_SHIFT) !=
(u16)core->core_index) {
val16 = ((u16)core->core_index << SRSH_PI_SHIFT) |
(val16 & ~SRSH_PI_MASK);
bcma_write16(pi->core, regoff, val16);
}
}
/* precondition: current core is pci core */
void
pcicore_pci_setup(struct pcicore_info *pi)
{
bcma_set32(pi->core, PCIREGOFFS(sbtopci2),
SBTOPCI_PREF | SBTOPCI_BURST);
if (pi->core->id.rev >= 11) {
bcma_set32(pi->core, PCIREGOFFS(sbtopci2),
SBTOPCI_RC_READMULTI);
bcma_set32(pi->core, PCIREGOFFS(clkrun), PCI_CLKRUN_DSBL);
(void)bcma_read32(pi->core, PCIREGOFFS(clkrun));
}
}

View File

@ -1,77 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_NICPCI_H_
#define _BRCM_NICPCI_H_
#include "types.h"
/* PCI configuration address space size */
#define PCI_SZPCR 256
/* Brcm PCI configuration registers */
/* backplane address space accessed by BAR0 */
#define PCI_BAR0_WIN 0x80
/* sprom property control */
#define PCI_SPROM_CONTROL 0x88
/* mask of PCI and other cores interrupts */
#define PCI_INT_MASK 0x94
/* backplane core interrupt mask bits offset */
#define PCI_SBIM_SHIFT 8
/* backplane address space accessed by second 4KB of BAR0 */
#define PCI_BAR0_WIN2 0xac
/* pci config space gpio input (>=rev3) */
#define PCI_GPIO_IN 0xb0
/* pci config space gpio output (>=rev3) */
#define PCI_GPIO_OUT 0xb4
/* pci config space gpio output enable (>=rev3) */
#define PCI_GPIO_OUTEN 0xb8
/* bar0 + 4K accesses external sprom */
#define PCI_BAR0_SPROM_OFFSET (4 * 1024)
/* bar0 + 6K accesses pci core registers */
#define PCI_BAR0_PCIREGS_OFFSET (6 * 1024)
/*
* pci core SB registers are at the end of the
* 8KB window, so their address is the "regular"
* address plus 4K
*/
#define PCI_BAR0_PCISBR_OFFSET (4 * 1024)
/* bar0 window size Match with corerev 13 */
#define PCI_BAR0_WINSZ (16 * 1024)
/* On pci corerev >= 13 and all pcie, the bar0 is now 16KB and it maps: */
/* bar0 + 8K accesses pci/pcie core registers */
#define PCI_16KB0_PCIREGS_OFFSET (8 * 1024)
/* bar0 + 12K accesses chipc core registers */
#define PCI_16KB0_CCREGS_OFFSET (12 * 1024)
struct sbpciregs;
struct sbpcieregs;
extern struct pcicore_info *pcicore_init(struct si_pub *sih,
struct bcma_device *core);
extern void pcicore_deinit(struct pcicore_info *pch);
extern void pcicore_attach(struct pcicore_info *pch, int state);
extern void pcicore_hwup(struct pcicore_info *pch);
extern void pcicore_up(struct pcicore_info *pch, int state);
extern void pcicore_sleep(struct pcicore_info *pch);
extern void pcicore_down(struct pcicore_info *pch, int state);
extern u8 pcicore_find_pci_capability(struct pci_dev *dev, u8 req_cap_id,
unsigned char *buf, u32 *buflen);
extern void pcicore_fixcfg(struct pcicore_info *pch);
extern void pcicore_pci_setup(struct pcicore_info *pch);
#endif /* _BRCM_NICPCI_H_ */

View File

@ -1,410 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/io.h>
#include <linux/errno.h>
#include <linux/string.h>
#include <brcm_hw_ids.h>
#include <chipcommon.h>
#include "aiutils.h"
#include "otp.h"
#define OTPS_GUP_MASK 0x00000f00
#define OTPS_GUP_SHIFT 8
/* h/w subregion is programmed */
#define OTPS_GUP_HW 0x00000100
/* s/w subregion is programmed */
#define OTPS_GUP_SW 0x00000200
/* chipid/pkgopt subregion is programmed */
#define OTPS_GUP_CI 0x00000400
/* fuse subregion is programmed */
#define OTPS_GUP_FUSE 0x00000800
/* Fields in otpprog in rev >= 21 */
#define OTPP_COL_MASK 0x000000ff
#define OTPP_COL_SHIFT 0
#define OTPP_ROW_MASK 0x0000ff00
#define OTPP_ROW_SHIFT 8
#define OTPP_OC_MASK 0x0f000000
#define OTPP_OC_SHIFT 24
#define OTPP_READERR 0x10000000
#define OTPP_VALUE_MASK 0x20000000
#define OTPP_VALUE_SHIFT 29
#define OTPP_START_BUSY 0x80000000
#define OTPP_READ 0x40000000
/* Opcodes for OTPP_OC field */
#define OTPPOC_READ 0
#define OTPPOC_BIT_PROG 1
#define OTPPOC_VERIFY 3
#define OTPPOC_INIT 4
#define OTPPOC_SET 5
#define OTPPOC_RESET 6
#define OTPPOC_OCST 7
#define OTPPOC_ROW_LOCK 8
#define OTPPOC_PRESCN_TEST 9
#define OTPTYPE_IPX(ccrev) ((ccrev) == 21 || (ccrev) >= 23)
#define OTPP_TRIES 10000000 /* # of tries for OTPP */
#define MAXNUMRDES 9 /* Maximum OTP redundancy entries */
/* Fixed size subregions sizes in words */
#define OTPGU_CI_SZ 2
struct otpinfo;
/* OTP function struct */
struct otp_fn_s {
int (*init)(struct si_pub *sih, struct otpinfo *oi);
int (*read_region)(struct otpinfo *oi, int region, u16 *data,
uint *wlen);
};
struct otpinfo {
struct bcma_device *core; /* chipc core */
const struct otp_fn_s *fn; /* OTP functions */
struct si_pub *sih; /* Saved sb handle */
/* IPX OTP section */
u16 wsize; /* Size of otp in words */
u16 rows; /* Geometry */
u16 cols; /* Geometry */
u32 status; /* Flag bits (lock/prog/rv).
* (Reflected only when OTP is power cycled)
*/
u16 hwbase; /* hardware subregion offset */
u16 hwlim; /* hardware subregion boundary */
u16 swbase; /* software subregion offset */
u16 swlim; /* software subregion boundary */
u16 fbase; /* fuse subregion offset */
u16 flim; /* fuse subregion boundary */
int otpgu_base; /* offset to General Use Region */
};
/* OTP layout */
/* CC revs 21, 24 and 27 OTP General Use Region word offset */
#define REVA4_OTPGU_BASE 12
/* CC revs 23, 25, 26, 28 and above OTP General Use Region word offset */
#define REVB8_OTPGU_BASE 20
/* CC rev 36 OTP General Use Region word offset */
#define REV36_OTPGU_BASE 12
/* Subregion word offsets in General Use region */
#define OTPGU_HSB_OFF 0
#define OTPGU_SFB_OFF 1
#define OTPGU_CI_OFF 2
#define OTPGU_P_OFF 3
#define OTPGU_SROM_OFF 4
/* Flag bit offsets in General Use region */
#define OTPGU_HWP_OFF 60
#define OTPGU_SWP_OFF 61
#define OTPGU_CIP_OFF 62
#define OTPGU_FUSEP_OFF 63
#define OTPGU_CIP_MSK 0x4000
#define OTPGU_P_MSK 0xf000
#define OTPGU_P_SHIFT (OTPGU_HWP_OFF % 16)
/* OTP Size */
#define OTP_SZ_FU_324 ((roundup(324, 8))/8) /* 324 bits */
#define OTP_SZ_FU_288 (288/8) /* 288 bits */
#define OTP_SZ_FU_216 (216/8) /* 216 bits */
#define OTP_SZ_FU_72 (72/8) /* 72 bits */
#define OTP_SZ_CHECKSUM (16/8) /* 16 bits */
#define OTP4315_SWREG_SZ 178 /* 178 bytes */
#define OTP_SZ_FU_144 (144/8) /* 144 bits */
static u16
ipxotp_otpr(struct otpinfo *oi, uint wn)
{
return bcma_read16(oi->core,
CHIPCREGOFFS(sromotp[wn]));
}
/*
* Calculate max HW/SW region byte size by subtracting fuse region
* and checksum size, osizew is oi->wsize (OTP size - GU size) in words
*/
static int ipxotp_max_rgnsz(struct si_pub *sih, int osizew)
{
int ret = 0;
switch (ai_get_chip_id(sih)) {
case BCM43224_CHIP_ID:
case BCM43225_CHIP_ID:
ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
break;
case BCM4313_CHIP_ID:
ret = osizew * 2 - OTP_SZ_FU_72 - OTP_SZ_CHECKSUM;
break;
default:
break; /* Don't know about this chip */
}
return ret;
}
static void _ipxotp_init(struct otpinfo *oi)
{
uint k;
u32 otpp, st;
int ccrev = ai_get_ccrev(oi->sih);
/*
* record word offset of General Use Region
* for various chipcommon revs
*/
if (ccrev == 21 || ccrev == 24
|| ccrev == 27) {
oi->otpgu_base = REVA4_OTPGU_BASE;
} else if (ccrev == 36) {
/*
* OTP size greater than equal to 2KB (128 words),
* otpgu_base is similar to rev23
*/
if (oi->wsize >= 128)
oi->otpgu_base = REVB8_OTPGU_BASE;
else
oi->otpgu_base = REV36_OTPGU_BASE;
} else if (ccrev == 23 || ccrev >= 25) {
oi->otpgu_base = REVB8_OTPGU_BASE;
}
/* First issue an init command so the status is up to date */
otpp =
OTPP_START_BUSY | ((OTPPOC_INIT << OTPP_OC_SHIFT) & OTPP_OC_MASK);
bcma_write32(oi->core, CHIPCREGOFFS(otpprog), otpp);
st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog));
for (k = 0; (st & OTPP_START_BUSY) && (k < OTPP_TRIES); k++)
st = bcma_read32(oi->core, CHIPCREGOFFS(otpprog));
if (k >= OTPP_TRIES)
return;
/* Read OTP lock bits and subregion programmed indication bits */
oi->status = bcma_read32(oi->core, CHIPCREGOFFS(otpstatus));
if ((ai_get_chip_id(oi->sih) == BCM43224_CHIP_ID)
|| (ai_get_chip_id(oi->sih) == BCM43225_CHIP_ID)) {
u32 p_bits;
p_bits = (ipxotp_otpr(oi, oi->otpgu_base + OTPGU_P_OFF) &
OTPGU_P_MSK) >> OTPGU_P_SHIFT;
oi->status |= (p_bits << OTPS_GUP_SHIFT);
}
/*
* h/w region base and fuse region limit are fixed to
* the top and the bottom of the general use region.
* Everything else can be flexible.
*/
oi->hwbase = oi->otpgu_base + OTPGU_SROM_OFF;
oi->hwlim = oi->wsize;
if (oi->status & OTPS_GUP_HW) {
oi->hwlim =
ipxotp_otpr(oi, oi->otpgu_base + OTPGU_HSB_OFF) / 16;
oi->swbase = oi->hwlim;
} else
oi->swbase = oi->hwbase;
/* subtract fuse and checksum from beginning */
oi->swlim = ipxotp_max_rgnsz(oi->sih, oi->wsize) / 2;
if (oi->status & OTPS_GUP_SW) {
oi->swlim =
ipxotp_otpr(oi, oi->otpgu_base + OTPGU_SFB_OFF) / 16;
oi->fbase = oi->swlim;
} else
oi->fbase = oi->swbase;
oi->flim = oi->wsize;
}
static int ipxotp_init(struct si_pub *sih, struct otpinfo *oi)
{
/* Make sure we're running IPX OTP */
if (!OTPTYPE_IPX(ai_get_ccrev(sih)))
return -EBADE;
/* Make sure OTP is not disabled */
if (ai_is_otp_disabled(sih))
return -EBADE;
/* Check for otp size */
switch ((ai_get_cccaps(sih) & CC_CAP_OTPSIZE) >> CC_CAP_OTPSIZE_SHIFT) {
case 0:
/* Nothing there */
return -EBADE;
case 1: /* 32x64 */
oi->rows = 32;
oi->cols = 64;
oi->wsize = 128;
break;
case 2: /* 64x64 */
oi->rows = 64;
oi->cols = 64;
oi->wsize = 256;
break;
case 5: /* 96x64 */
oi->rows = 96;
oi->cols = 64;
oi->wsize = 384;
break;
case 7: /* 16x64 *//* 1024 bits */
oi->rows = 16;
oi->cols = 64;
oi->wsize = 64;
break;
default:
/* Don't know the geometry */
return -EBADE;
}
/* Retrieve OTP region info */
_ipxotp_init(oi);
return 0;
}
static int
ipxotp_read_region(struct otpinfo *oi, int region, u16 *data, uint *wlen)
{
uint base, i, sz;
/* Validate region selection */
switch (region) {
case OTP_HW_RGN:
sz = (uint) oi->hwlim - oi->hwbase;
if (!(oi->status & OTPS_GUP_HW)) {
*wlen = sz;
return -ENODATA;
}
if (*wlen < sz) {
*wlen = sz;
return -EOVERFLOW;
}
base = oi->hwbase;
break;
case OTP_SW_RGN:
sz = ((uint) oi->swlim - oi->swbase);
if (!(oi->status & OTPS_GUP_SW)) {
*wlen = sz;
return -ENODATA;
}
if (*wlen < sz) {
*wlen = sz;
return -EOVERFLOW;
}
base = oi->swbase;
break;
case OTP_CI_RGN:
sz = OTPGU_CI_SZ;
if (!(oi->status & OTPS_GUP_CI)) {
*wlen = sz;
return -ENODATA;
}
if (*wlen < sz) {
*wlen = sz;
return -EOVERFLOW;
}
base = oi->otpgu_base + OTPGU_CI_OFF;
break;
case OTP_FUSE_RGN:
sz = (uint) oi->flim - oi->fbase;
if (!(oi->status & OTPS_GUP_FUSE)) {
*wlen = sz;
return -ENODATA;
}
if (*wlen < sz) {
*wlen = sz;
return -EOVERFLOW;
}
base = oi->fbase;
break;
case OTP_ALL_RGN:
sz = ((uint) oi->flim - oi->hwbase);
if (!(oi->status & (OTPS_GUP_HW | OTPS_GUP_SW))) {
*wlen = sz;
return -ENODATA;
}
if (*wlen < sz) {
*wlen = sz;
return -EOVERFLOW;
}
base = oi->hwbase;
break;
default:
return -EINVAL;
}
/* Read the data */
for (i = 0; i < sz; i++)
data[i] = ipxotp_otpr(oi, base + i);
*wlen = sz;
return 0;
}
static const struct otp_fn_s ipxotp_fn = {
(int (*)(struct si_pub *, struct otpinfo *)) ipxotp_init,
(int (*)(struct otpinfo *, int, u16 *, uint *)) ipxotp_read_region,
};
static int otp_init(struct si_pub *sih, struct otpinfo *oi)
{
int ret;
memset(oi, 0, sizeof(struct otpinfo));
oi->core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0);
if (OTPTYPE_IPX(ai_get_ccrev(sih)))
oi->fn = &ipxotp_fn;
if (oi->fn == NULL)
return -EBADE;
oi->sih = sih;
ret = (oi->fn->init)(sih, oi);
return ret;
}
int
otp_read_region(struct si_pub *sih, int region, u16 *data, uint *wlen) {
struct otpinfo otpinfo;
struct otpinfo *oi = &otpinfo;
int err = 0;
if (ai_is_otp_disabled(sih)) {
err = -EPERM;
goto out;
}
err = otp_init(sih, oi);
if (err)
goto out;
err = ((oi)->fn->read_region)(oi, region, data, wlen);
out:
return err;
}

View File

@ -1,36 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_OTP_H_
#define _BRCM_OTP_H_
#include "types.h"
/* OTP regions */
#define OTP_HW_RGN 1
#define OTP_SW_RGN 2
#define OTP_CI_RGN 4
#define OTP_FUSE_RGN 8
/* From h/w region to end of OTP including checksum */
#define OTP_ALL_RGN 0xf
/* OTP Size */
#define OTP_SZ_MAX (6144/8) /* maximum bytes in one CIS */
extern int otp_read_region(struct si_pub *sih, int region, u16 *data,
uint *wlen);
#endif /* _BRCM_OTP_H_ */

View File

@ -4817,28 +4817,23 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
s8 txpwr = 0;
int i;
struct brcms_phy_lcnphy *pi_lcn = pi->u.pi_lcnphy;
struct phy_shim_info *shim = pi->sh->physhim;
struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
if (CHSPEC_IS2G(pi->radio_chanspec)) {
u16 cckpo = 0;
u32 offset_ofdm, offset_mcs;
pi_lcn->lcnphy_tr_isolation_mid =
(u8)wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
pi_lcn->lcnphy_tr_isolation_mid = sprom->fem.ghz2.tr_iso;
pi_lcn->lcnphy_rx_power_offset =
(u8)wlapi_getintvar(shim, BRCMS_SROM_RXPO2G);
pi_lcn->lcnphy_rx_power_offset = sprom->rxpo2g;
pi->txpa_2g[0] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B0);
pi->txpa_2g[1] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B1);
pi->txpa_2g[2] = (s16)wlapi_getintvar(shim, BRCMS_SROM_PA0B2);
pi->txpa_2g[0] = sprom->pa0b0;
pi->txpa_2g[1] = sprom->pa0b1;
pi->txpa_2g[2] = sprom->pa0b2;
pi_lcn->lcnphy_rssi_vf =
(u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMF2G);
pi_lcn->lcnphy_rssi_vc =
(u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISMC2G);
pi_lcn->lcnphy_rssi_gs =
(u8)wlapi_getintvar(shim, BRCMS_SROM_RSSISAV2G);
pi_lcn->lcnphy_rssi_vf = sprom->rssismf2g;
pi_lcn->lcnphy_rssi_vc = sprom->rssismc2g;
pi_lcn->lcnphy_rssi_gs = sprom->rssisav2g;
pi_lcn->lcnphy_rssi_vf_lowtemp = pi_lcn->lcnphy_rssi_vf;
pi_lcn->lcnphy_rssi_vc_lowtemp = pi_lcn->lcnphy_rssi_vc;
@ -4848,7 +4843,7 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
pi_lcn->lcnphy_rssi_vc_hightemp = pi_lcn->lcnphy_rssi_vc;
pi_lcn->lcnphy_rssi_gs_hightemp = pi_lcn->lcnphy_rssi_gs;
txpwr = (s8)wlapi_getintvar(shim, BRCMS_SROM_MAXP2GA0);
txpwr = sprom->core_pwr_info[0].maxpwr_2g;
pi->tx_srom_max_2g = txpwr;
for (i = 0; i < PWRTBL_NUM_COEFF; i++) {
@ -4856,8 +4851,8 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
pi->txpa_2g_high_temp[i] = pi->txpa_2g[i];
}
cckpo = (u16)wlapi_getintvar(shim, BRCMS_SROM_CCK2GPO);
offset_ofdm = (u32)wlapi_getintvar(shim, BRCMS_SROM_OFDM2GPO);
cckpo = sprom->cck2gpo;
offset_ofdm = sprom->ofdm2gpo;
if (cckpo) {
uint max_pwr_chan = txpwr;
@ -4876,7 +4871,7 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
} else {
u8 opo = 0;
opo = (u8)wlapi_getintvar(shim, BRCMS_SROM_OPO);
opo = sprom->opo;
for (i = TXP_FIRST_CCK; i <= TXP_LAST_CCK; i++)
pi->tx_srom_max_rate_2g[i] = txpwr;
@ -4886,12 +4881,8 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
((offset_ofdm & 0xf) * 2);
offset_ofdm >>= 4;
}
offset_mcs =
wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO1) << 16;
offset_mcs |=
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO0);
offset_mcs = sprom->mcs2gpo[1] << 16;
offset_mcs |= sprom->mcs2gpo[0];
pi_lcn->lcnphy_mcs20_po = offset_mcs;
for (i = TXP_FIRST_SISO_MCS_20;
i <= TXP_LAST_SISO_MCS_20; i++) {
@ -4901,25 +4892,17 @@ static bool wlc_phy_txpwr_srom_read_lcnphy(struct brcms_phy *pi)
}
}
pi_lcn->lcnphy_rawtempsense =
(u16)wlapi_getintvar(shim, BRCMS_SROM_RAWTEMPSENSE);
pi_lcn->lcnphy_measPower =
(u8)wlapi_getintvar(shim, BRCMS_SROM_MEASPOWER);
pi_lcn->lcnphy_tempsense_slope =
(u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_SLOPE);
pi_lcn->lcnphy_hw_iqcal_en =
(bool)wlapi_getintvar(shim, BRCMS_SROM_HW_IQCAL_EN);
pi_lcn->lcnphy_iqcal_swp_dis =
(bool)wlapi_getintvar(shim, BRCMS_SROM_IQCAL_SWP_DIS);
pi_lcn->lcnphy_tempcorrx =
(u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPCORRX);
pi_lcn->lcnphy_tempsense_option =
(u8)wlapi_getintvar(shim, BRCMS_SROM_TEMPSENSE_OPTION);
pi_lcn->lcnphy_freqoffset_corr =
(u8)wlapi_getintvar(shim, BRCMS_SROM_FREQOFFSET_CORR);
if ((u8)wlapi_getintvar(shim, BRCMS_SROM_AA2G) > 1)
pi_lcn->lcnphy_rawtempsense = sprom->rawtempsense;
pi_lcn->lcnphy_measPower = sprom->measpower;
pi_lcn->lcnphy_tempsense_slope = sprom->tempsense_slope;
pi_lcn->lcnphy_hw_iqcal_en = sprom->hw_iqcal_en;
pi_lcn->lcnphy_iqcal_swp_dis = sprom->iqcal_swp_dis;
pi_lcn->lcnphy_tempcorrx = sprom->tempcorrx;
pi_lcn->lcnphy_tempsense_option = sprom->tempsense_option;
pi_lcn->lcnphy_freqoffset_corr = sprom->freqoffset_corr;
if (sprom->ant_available_bg > 1)
wlc_phy_ant_rxdiv_set((struct brcms_phy_pub *) pi,
(u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G));
sprom->ant_available_bg);
}
pi_lcn->lcnphy_cck_dig_filt_type = -1;

View File

@ -14386,30 +14386,30 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
{
u16 bw40po, cddpo, stbcpo, bwduppo;
uint band_num;
struct phy_shim_info *shim = pi->sh->physhim;
struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
if (pi->sh->sromrev >= 9)
return;
bw40po = (u16) wlapi_getintvar(shim, BRCMS_SROM_BW40PO);
bw40po = sprom->bw40po;
pi->bw402gpo = bw40po & 0xf;
pi->bw405gpo = (bw40po & 0xf0) >> 4;
pi->bw405glpo = (bw40po & 0xf00) >> 8;
pi->bw405ghpo = (bw40po & 0xf000) >> 12;
cddpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_CDDPO);
cddpo = sprom->cddpo;
pi->cdd2gpo = cddpo & 0xf;
pi->cdd5gpo = (cddpo & 0xf0) >> 4;
pi->cdd5glpo = (cddpo & 0xf00) >> 8;
pi->cdd5ghpo = (cddpo & 0xf000) >> 12;
stbcpo = (u16) wlapi_getintvar(shim, BRCMS_SROM_STBCPO);
stbcpo = sprom->stbcpo;
pi->stbc2gpo = stbcpo & 0xf;
pi->stbc5gpo = (stbcpo & 0xf0) >> 4;
pi->stbc5glpo = (stbcpo & 0xf00) >> 8;
pi->stbc5ghpo = (stbcpo & 0xf000) >> 12;
bwduppo = (u16) wlapi_getintvar(shim, BRCMS_SROM_BWDUPPO);
bwduppo = sprom->bwduppo;
pi->bwdup2gpo = bwduppo & 0xf;
pi->bwdup5gpo = (bwduppo & 0xf0) >> 4;
pi->bwdup5glpo = (bwduppo & 0xf00) >> 8;
@ -14419,242 +14419,137 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
band_num++) {
switch (band_num) {
case 0:
pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_2g =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP2GA0);
sprom->core_pwr_info[0].maxpwr_2g;
pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_2g =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP2GA1);
sprom->core_pwr_info[1].maxpwr_2g;
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW0A0);
sprom->core_pwr_info[0].pa_2g[0];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW0A1);
sprom->core_pwr_info[1].pa_2g[0];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW1A0);
sprom->core_pwr_info[0].pa_2g[1];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW1A1);
sprom->core_pwr_info[1].pa_2g[1];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_2g_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW2A0);
sprom->core_pwr_info[0].pa_2g[2];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_2g_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA2GW2A1);
sprom->core_pwr_info[1].pa_2g[2];
pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_2g =
(s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA0);
sprom->core_pwr_info[0].itssi_2g;
pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_2g =
(s8) wlapi_getintvar(shim, BRCMS_SROM_ITT2GA1);
sprom->core_pwr_info[1].itssi_2g;
pi->cck2gpo = (u16) wlapi_getintvar(shim,
BRCMS_SROM_CCK2GPO);
pi->cck2gpo = sprom->cck2gpo;
pi->ofdm2gpo =
(u32) wlapi_getintvar(shim,
BRCMS_SROM_OFDM2GPO);
pi->ofdm2gpo = sprom->ofdm2gpo;
pi->mcs2gpo[0] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO0);
pi->mcs2gpo[1] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO1);
pi->mcs2gpo[2] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO2);
pi->mcs2gpo[3] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO3);
pi->mcs2gpo[4] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO4);
pi->mcs2gpo[5] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO5);
pi->mcs2gpo[6] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO6);
pi->mcs2gpo[7] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS2GPO7);
pi->mcs2gpo[0] = sprom->mcs2gpo[0];
pi->mcs2gpo[1] = sprom->mcs2gpo[1];
pi->mcs2gpo[2] = sprom->mcs2gpo[2];
pi->mcs2gpo[3] = sprom->mcs2gpo[3];
pi->mcs2gpo[4] = sprom->mcs2gpo[4];
pi->mcs2gpo[5] = sprom->mcs2gpo[5];
pi->mcs2gpo[6] = sprom->mcs2gpo[6];
pi->mcs2gpo[7] = sprom->mcs2gpo[7];
break;
case 1:
pi->nphy_pwrctrl_info[PHY_CORE_0].max_pwr_5gm =
(s8) wlapi_getintvar(shim, BRCMS_SROM_MAXP5GA0);
sprom->core_pwr_info[0].maxpwr_5g;
pi->nphy_pwrctrl_info[PHY_CORE_1].max_pwr_5gm =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP5GA1);
sprom->core_pwr_info[1].maxpwr_5g;
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW0A0);
sprom->core_pwr_info[0].pa_5g[0];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW0A1);
sprom->core_pwr_info[1].pa_5g[0];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW1A0);
sprom->core_pwr_info[0].pa_5g[1];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW1A1);
sprom->core_pwr_info[1].pa_5g[1];
pi->nphy_pwrctrl_info[PHY_CORE_0].pwrdet_5gm_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW2A0);
sprom->core_pwr_info[0].pa_5g[2];
pi->nphy_pwrctrl_info[PHY_CORE_1].pwrdet_5gm_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GW2A1);
sprom->core_pwr_info[1].pa_5g[2];
pi->nphy_pwrctrl_info[PHY_CORE_0].idle_targ_5gm =
(s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA0);
sprom->core_pwr_info[0].itssi_5g;
pi->nphy_pwrctrl_info[PHY_CORE_1].idle_targ_5gm =
(s8) wlapi_getintvar(shim, BRCMS_SROM_ITT5GA1);
sprom->core_pwr_info[1].itssi_5g;
pi->ofdm5gpo =
(u32) wlapi_getintvar(shim,
BRCMS_SROM_OFDM5GPO);
pi->ofdm5gpo = sprom->ofdm5gpo;
pi->mcs5gpo[0] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO0);
pi->mcs5gpo[1] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO1);
pi->mcs5gpo[2] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO2);
pi->mcs5gpo[3] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO3);
pi->mcs5gpo[4] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO4);
pi->mcs5gpo[5] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO5);
pi->mcs5gpo[6] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO6);
pi->mcs5gpo[7] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GPO7);
pi->mcs5gpo[0] = sprom->mcs5gpo[0];
pi->mcs5gpo[1] = sprom->mcs5gpo[1];
pi->mcs5gpo[2] = sprom->mcs5gpo[2];
pi->mcs5gpo[3] = sprom->mcs5gpo[3];
pi->mcs5gpo[4] = sprom->mcs5gpo[4];
pi->mcs5gpo[5] = sprom->mcs5gpo[5];
pi->mcs5gpo[6] = sprom->mcs5gpo[6];
pi->mcs5gpo[7] = sprom->mcs5gpo[7];
break;
case 2:
pi->nphy_pwrctrl_info[0].max_pwr_5gl =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP5GLA0);
sprom->core_pwr_info[0].maxpwr_5gl;
pi->nphy_pwrctrl_info[1].max_pwr_5gl =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP5GLA1);
sprom->core_pwr_info[1].maxpwr_5gl;
pi->nphy_pwrctrl_info[0].pwrdet_5gl_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW0A0);
sprom->core_pwr_info[0].pa_5gl[0];
pi->nphy_pwrctrl_info[1].pwrdet_5gl_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW0A1);
sprom->core_pwr_info[1].pa_5gl[0];
pi->nphy_pwrctrl_info[0].pwrdet_5gl_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW1A0);
sprom->core_pwr_info[0].pa_5gl[1];
pi->nphy_pwrctrl_info[1].pwrdet_5gl_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW1A1);
sprom->core_pwr_info[1].pa_5gl[1];
pi->nphy_pwrctrl_info[0].pwrdet_5gl_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW2A0);
sprom->core_pwr_info[0].pa_5gl[2];
pi->nphy_pwrctrl_info[1].pwrdet_5gl_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GLW2A1);
sprom->core_pwr_info[1].pa_5gl[2];
pi->nphy_pwrctrl_info[0].idle_targ_5gl = 0;
pi->nphy_pwrctrl_info[1].idle_targ_5gl = 0;
pi->ofdm5glpo =
(u32) wlapi_getintvar(shim,
BRCMS_SROM_OFDM5GLPO);
pi->ofdm5glpo = sprom->ofdm5glpo;
pi->mcs5glpo[0] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO0);
pi->mcs5glpo[1] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO1);
pi->mcs5glpo[2] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO2);
pi->mcs5glpo[3] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO3);
pi->mcs5glpo[4] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO4);
pi->mcs5glpo[5] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO5);
pi->mcs5glpo[6] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO6);
pi->mcs5glpo[7] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GLPO7);
pi->mcs5glpo[0] = sprom->mcs5glpo[0];
pi->mcs5glpo[1] = sprom->mcs5glpo[1];
pi->mcs5glpo[2] = sprom->mcs5glpo[2];
pi->mcs5glpo[3] = sprom->mcs5glpo[3];
pi->mcs5glpo[4] = sprom->mcs5glpo[4];
pi->mcs5glpo[5] = sprom->mcs5glpo[5];
pi->mcs5glpo[6] = sprom->mcs5glpo[6];
pi->mcs5glpo[7] = sprom->mcs5glpo[7];
break;
case 3:
pi->nphy_pwrctrl_info[0].max_pwr_5gh =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP5GHA0);
sprom->core_pwr_info[0].maxpwr_5gh;
pi->nphy_pwrctrl_info[1].max_pwr_5gh =
(s8) wlapi_getintvar(shim,
BRCMS_SROM_MAXP5GHA1);
sprom->core_pwr_info[1].maxpwr_5gh;
pi->nphy_pwrctrl_info[0].pwrdet_5gh_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW0A0);
sprom->core_pwr_info[0].pa_5gh[0];
pi->nphy_pwrctrl_info[1].pwrdet_5gh_a1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW0A1);
sprom->core_pwr_info[1].pa_5gh[0];
pi->nphy_pwrctrl_info[0].pwrdet_5gh_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW1A0);
sprom->core_pwr_info[0].pa_5gh[1];
pi->nphy_pwrctrl_info[1].pwrdet_5gh_b0 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW1A1);
sprom->core_pwr_info[1].pa_5gh[1];
pi->nphy_pwrctrl_info[0].pwrdet_5gh_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW2A0);
sprom->core_pwr_info[0].pa_5gh[2];
pi->nphy_pwrctrl_info[1].pwrdet_5gh_b1 =
(s16) wlapi_getintvar(shim,
BRCMS_SROM_PA5GHW2A1);
sprom->core_pwr_info[1].pa_5gh[2];
pi->nphy_pwrctrl_info[0].idle_targ_5gh = 0;
pi->nphy_pwrctrl_info[1].idle_targ_5gh = 0;
pi->ofdm5ghpo =
(u32) wlapi_getintvar(shim,
BRCMS_SROM_OFDM5GHPO);
pi->ofdm5ghpo = sprom->ofdm5ghpo;
pi->mcs5ghpo[0] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO0);
pi->mcs5ghpo[1] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO1);
pi->mcs5ghpo[2] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO2);
pi->mcs5ghpo[3] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO3);
pi->mcs5ghpo[4] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO4);
pi->mcs5ghpo[5] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO5);
pi->mcs5ghpo[6] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO6);
pi->mcs5ghpo[7] =
(u16) wlapi_getintvar(shim,
BRCMS_SROM_MCS5GHPO7);
pi->mcs5ghpo[0] = sprom->mcs5ghpo[0];
pi->mcs5ghpo[1] = sprom->mcs5ghpo[1];
pi->mcs5ghpo[2] = sprom->mcs5ghpo[2];
pi->mcs5ghpo[3] = sprom->mcs5ghpo[3];
pi->mcs5ghpo[4] = sprom->mcs5ghpo[4];
pi->mcs5ghpo[5] = sprom->mcs5ghpo[5];
pi->mcs5ghpo[6] = sprom->mcs5ghpo[6];
pi->mcs5ghpo[7] = sprom->mcs5ghpo[7];
break;
}
}
@ -14664,45 +14559,34 @@ static void wlc_phy_txpwr_srom_read_ppr_nphy(struct brcms_phy *pi)
static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi)
{
struct phy_shim_info *shim = pi->sh->physhim;
struct ssb_sprom *sprom = &pi->d11core->bus->sprom;
pi->antswitch = (u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWITCH);
pi->aa2g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA2G);
pi->aa5g = (u8) wlapi_getintvar(shim, BRCMS_SROM_AA5G);
pi->antswitch = sprom->antswitch;
pi->aa2g = sprom->ant_available_bg;
pi->aa5g = sprom->ant_available_a;
pi->srom_fem2g.tssipos = (u8) wlapi_getintvar(shim,
BRCMS_SROM_TSSIPOS2G);
pi->srom_fem2g.extpagain = (u8) wlapi_getintvar(shim,
BRCMS_SROM_EXTPAGAIN2G);
pi->srom_fem2g.pdetrange = (u8) wlapi_getintvar(shim,
BRCMS_SROM_PDETRANGE2G);
pi->srom_fem2g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO2G);
pi->srom_fem2g.antswctrllut =
(u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G);
pi->srom_fem2g.tssipos = sprom->fem.ghz2.tssipos;
pi->srom_fem2g.extpagain = sprom->fem.ghz2.extpa_gain;
pi->srom_fem2g.pdetrange = sprom->fem.ghz2.pdet_range;
pi->srom_fem2g.triso = sprom->fem.ghz2.tr_iso;
pi->srom_fem2g.antswctrllut = sprom->fem.ghz2.antswlut;
pi->srom_fem5g.tssipos = (u8) wlapi_getintvar(shim,
BRCMS_SROM_TSSIPOS5G);
pi->srom_fem5g.extpagain = (u8) wlapi_getintvar(shim,
BRCMS_SROM_EXTPAGAIN5G);
pi->srom_fem5g.pdetrange = (u8) wlapi_getintvar(shim,
BRCMS_SROM_PDETRANGE5G);
pi->srom_fem5g.triso = (u8) wlapi_getintvar(shim, BRCMS_SROM_TRISO5G);
if (wlapi_getvar(shim, BRCMS_SROM_ANTSWCTL5G))
pi->srom_fem5g.antswctrllut =
(u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL5G);
pi->srom_fem5g.tssipos = sprom->fem.ghz5.tssipos;
pi->srom_fem5g.extpagain = sprom->fem.ghz5.extpa_gain;
pi->srom_fem5g.pdetrange = sprom->fem.ghz5.pdet_range;
pi->srom_fem5g.triso = sprom->fem.ghz5.tr_iso;
if (sprom->fem.ghz5.antswlut)
pi->srom_fem5g.antswctrllut = sprom->fem.ghz5.antswlut;
else
pi->srom_fem5g.antswctrllut =
(u8) wlapi_getintvar(shim, BRCMS_SROM_ANTSWCTL2G);
pi->srom_fem5g.antswctrllut = sprom->fem.ghz2.antswlut;
wlc_phy_txpower_ipa_upd(pi);
pi->phy_txcore_disable_temp =
(s16) wlapi_getintvar(shim, BRCMS_SROM_TEMPTHRESH);
pi->phy_txcore_disable_temp = sprom->tempthresh;
if (pi->phy_txcore_disable_temp == 0)
pi->phy_txcore_disable_temp = PHY_CHAIN_TX_DISABLE_TEMP;
pi->phy_tempsense_offset = (s8) wlapi_getintvar(shim,
BRCMS_SROM_TEMPOFFSET);
pi->phy_tempsense_offset = sprom->tempoffset;
if (pi->phy_tempsense_offset != 0) {
if (pi->phy_tempsense_offset >
(NPHY_SROM_TEMPSHIFT + NPHY_SROM_MAXTEMPOFFSET))
@ -14717,8 +14601,7 @@ static bool wlc_phy_txpwr_srom_read_nphy(struct brcms_phy *pi)
pi->phy_txcore_enable_temp =
pi->phy_txcore_disable_temp - PHY_HYSTERESIS_DELTATEMP;
pi->phycal_tempdelta =
(u8) wlapi_getintvar(shim, BRCMS_SROM_PHYCAL_TEMPDELTA);
pi->phycal_tempdelta = sprom->phycal_tempdelta;
if (pi->phycal_tempdelta > NPHY_CAL_MAXTEMPDELTA)
pi->phycal_tempdelta = 0;
@ -21460,7 +21343,7 @@ void wlc_phy_antsel_init(struct brcms_phy_pub *ppi, bool lut_init)
write_phy_reg(pi, 0xc8, 0x0);
write_phy_reg(pi, 0xc9, 0x0);
ai_gpiocontrol(pi->sh->sih, mask, mask, GPIO_DRV_PRIORITY);
bcma_chipco_gpio_control(&pi->d11core->bus->drv_cc, mask, mask);
mc = bcma_read32(pi->d11core, D11REGOFFS(maccontrol));
mc &= ~MCTL_GPOUT_SEL_MASK;

View File

@ -214,12 +214,3 @@ wlapi_copyto_objmem(struct phy_shim_info *physhim, uint offset, const void *buf,
{
brcms_b_copyto_objmem(physhim->wlc_hw, offset, buf, l, sel);
}
char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id)
{
return getvar(physhim->wlc_hw->sih, id);
}
int wlapi_getintvar(struct phy_shim_info *physhim, enum brcms_srom_id id)
{
return getintvar(physhim->wlc_hw->sih, id);
}

View File

@ -175,8 +175,5 @@ extern void wlapi_copyto_objmem(struct phy_shim_info *physhim, uint,
extern void wlapi_high_update_phy_mode(struct phy_shim_info *physhim,
u32 phy_mode);
extern u16 wlapi_bmac_get_txant(struct phy_shim_info *physhim);
extern char *wlapi_getvar(struct phy_shim_info *physhim, enum brcms_srom_id id);
extern int wlapi_getintvar(struct phy_shim_info *physhim,
enum brcms_srom_id id);
#endif /* _BRCM_PHY_SHIM_H_ */

View File

@ -22,232 +22,6 @@
#include "types.h"
#include "defs.h"
enum brcms_srom_id {
BRCMS_SROM_NULL,
BRCMS_SROM_CONT,
BRCMS_SROM_AA2G,
BRCMS_SROM_AA5G,
BRCMS_SROM_AG0,
BRCMS_SROM_AG1,
BRCMS_SROM_AG2,
BRCMS_SROM_AG3,
BRCMS_SROM_ANTSWCTL2G,
BRCMS_SROM_ANTSWCTL5G,
BRCMS_SROM_ANTSWITCH,
BRCMS_SROM_BOARDFLAGS2,
BRCMS_SROM_BOARDFLAGS,
BRCMS_SROM_BOARDNUM,
BRCMS_SROM_BOARDREV,
BRCMS_SROM_BOARDTYPE,
BRCMS_SROM_BW40PO,
BRCMS_SROM_BWDUPPO,
BRCMS_SROM_BXA2G,
BRCMS_SROM_BXA5G,
BRCMS_SROM_CC,
BRCMS_SROM_CCK2GPO,
BRCMS_SROM_CCKBW202GPO,
BRCMS_SROM_CCKBW20UL2GPO,
BRCMS_SROM_CCODE,
BRCMS_SROM_CDDPO,
BRCMS_SROM_DEVID,
BRCMS_SROM_ET1MACADDR,
BRCMS_SROM_EXTPAGAIN2G,
BRCMS_SROM_EXTPAGAIN5G,
BRCMS_SROM_FREQOFFSET_CORR,
BRCMS_SROM_HW_IQCAL_EN,
BRCMS_SROM_IL0MACADDR,
BRCMS_SROM_IQCAL_SWP_DIS,
BRCMS_SROM_LEDBH0,
BRCMS_SROM_LEDBH1,
BRCMS_SROM_LEDBH2,
BRCMS_SROM_LEDBH3,
BRCMS_SROM_LEDDC,
BRCMS_SROM_LEGOFDM40DUPPO,
BRCMS_SROM_LEGOFDMBW202GPO,
BRCMS_SROM_LEGOFDMBW205GHPO,
BRCMS_SROM_LEGOFDMBW205GLPO,
BRCMS_SROM_LEGOFDMBW205GMPO,
BRCMS_SROM_LEGOFDMBW20UL2GPO,
BRCMS_SROM_LEGOFDMBW20UL5GHPO,
BRCMS_SROM_LEGOFDMBW20UL5GLPO,
BRCMS_SROM_LEGOFDMBW20UL5GMPO,
BRCMS_SROM_MACADDR,
BRCMS_SROM_MCS2GPO0,
BRCMS_SROM_MCS2GPO1,
BRCMS_SROM_MCS2GPO2,
BRCMS_SROM_MCS2GPO3,
BRCMS_SROM_MCS2GPO4,
BRCMS_SROM_MCS2GPO5,
BRCMS_SROM_MCS2GPO6,
BRCMS_SROM_MCS2GPO7,
BRCMS_SROM_MCS32PO,
BRCMS_SROM_MCS5GHPO0,
BRCMS_SROM_MCS5GHPO1,
BRCMS_SROM_MCS5GHPO2,
BRCMS_SROM_MCS5GHPO3,
BRCMS_SROM_MCS5GHPO4,
BRCMS_SROM_MCS5GHPO5,
BRCMS_SROM_MCS5GHPO6,
BRCMS_SROM_MCS5GHPO7,
BRCMS_SROM_MCS5GLPO0,
BRCMS_SROM_MCS5GLPO1,
BRCMS_SROM_MCS5GLPO2,
BRCMS_SROM_MCS5GLPO3,
BRCMS_SROM_MCS5GLPO4,
BRCMS_SROM_MCS5GLPO5,
BRCMS_SROM_MCS5GLPO6,
BRCMS_SROM_MCS5GLPO7,
BRCMS_SROM_MCS5GPO0,
BRCMS_SROM_MCS5GPO1,
BRCMS_SROM_MCS5GPO2,
BRCMS_SROM_MCS5GPO3,
BRCMS_SROM_MCS5GPO4,
BRCMS_SROM_MCS5GPO5,
BRCMS_SROM_MCS5GPO6,
BRCMS_SROM_MCS5GPO7,
BRCMS_SROM_MCSBW202GPO,
BRCMS_SROM_MCSBW205GHPO,
BRCMS_SROM_MCSBW205GLPO,
BRCMS_SROM_MCSBW205GMPO,
BRCMS_SROM_MCSBW20UL2GPO,
BRCMS_SROM_MCSBW20UL5GHPO,
BRCMS_SROM_MCSBW20UL5GLPO,
BRCMS_SROM_MCSBW20UL5GMPO,
BRCMS_SROM_MCSBW402GPO,
BRCMS_SROM_MCSBW405GHPO,
BRCMS_SROM_MCSBW405GLPO,
BRCMS_SROM_MCSBW405GMPO,
BRCMS_SROM_MEASPOWER,
BRCMS_SROM_OFDM2GPO,
BRCMS_SROM_OFDM5GHPO,
BRCMS_SROM_OFDM5GLPO,
BRCMS_SROM_OFDM5GPO,
BRCMS_SROM_OPO,
BRCMS_SROM_PA0B0,
BRCMS_SROM_PA0B1,
BRCMS_SROM_PA0B2,
BRCMS_SROM_PA0ITSSIT,
BRCMS_SROM_PA0MAXPWR,
BRCMS_SROM_PA1B0,
BRCMS_SROM_PA1B1,
BRCMS_SROM_PA1B2,
BRCMS_SROM_PA1HIB0,
BRCMS_SROM_PA1HIB1,
BRCMS_SROM_PA1HIB2,
BRCMS_SROM_PA1HIMAXPWR,
BRCMS_SROM_PA1ITSSIT,
BRCMS_SROM_PA1LOB0,
BRCMS_SROM_PA1LOB1,
BRCMS_SROM_PA1LOB2,
BRCMS_SROM_PA1LOMAXPWR,
BRCMS_SROM_PA1MAXPWR,
BRCMS_SROM_PDETRANGE2G,
BRCMS_SROM_PDETRANGE5G,
BRCMS_SROM_PHYCAL_TEMPDELTA,
BRCMS_SROM_RAWTEMPSENSE,
BRCMS_SROM_REGREV,
BRCMS_SROM_REV,
BRCMS_SROM_RSSISAV2G,
BRCMS_SROM_RSSISAV5G,
BRCMS_SROM_RSSISMC2G,
BRCMS_SROM_RSSISMC5G,
BRCMS_SROM_RSSISMF2G,
BRCMS_SROM_RSSISMF5G,
BRCMS_SROM_RXCHAIN,
BRCMS_SROM_RXPO2G,
BRCMS_SROM_RXPO5G,
BRCMS_SROM_STBCPO,
BRCMS_SROM_TEMPCORRX,
BRCMS_SROM_TEMPOFFSET,
BRCMS_SROM_TEMPSENSE_OPTION,
BRCMS_SROM_TEMPSENSE_SLOPE,
BRCMS_SROM_TEMPTHRESH,
BRCMS_SROM_TRI2G,
BRCMS_SROM_TRI5GH,
BRCMS_SROM_TRI5GL,
BRCMS_SROM_TRI5G,
BRCMS_SROM_TRISO2G,
BRCMS_SROM_TRISO5G,
BRCMS_SROM_TSSIPOS2G,
BRCMS_SROM_TSSIPOS5G,
BRCMS_SROM_TXCHAIN,
/*
* per-path identifiers (see srom.c)
*/
BRCMS_SROM_ITT2GA0,
BRCMS_SROM_ITT2GA1,
BRCMS_SROM_ITT2GA2,
BRCMS_SROM_ITT2GA3,
BRCMS_SROM_ITT5GA0,
BRCMS_SROM_ITT5GA1,
BRCMS_SROM_ITT5GA2,
BRCMS_SROM_ITT5GA3,
BRCMS_SROM_MAXP2GA0,
BRCMS_SROM_MAXP2GA1,
BRCMS_SROM_MAXP2GA2,
BRCMS_SROM_MAXP2GA3,
BRCMS_SROM_MAXP5GA0,
BRCMS_SROM_MAXP5GA1,
BRCMS_SROM_MAXP5GA2,
BRCMS_SROM_MAXP5GA3,
BRCMS_SROM_MAXP5GHA0,
BRCMS_SROM_MAXP5GHA1,
BRCMS_SROM_MAXP5GHA2,
BRCMS_SROM_MAXP5GHA3,
BRCMS_SROM_MAXP5GLA0,
BRCMS_SROM_MAXP5GLA1,
BRCMS_SROM_MAXP5GLA2,
BRCMS_SROM_MAXP5GLA3,
BRCMS_SROM_PA2GW0A0,
BRCMS_SROM_PA2GW0A1,
BRCMS_SROM_PA2GW0A2,
BRCMS_SROM_PA2GW0A3,
BRCMS_SROM_PA2GW1A0,
BRCMS_SROM_PA2GW1A1,
BRCMS_SROM_PA2GW1A2,
BRCMS_SROM_PA2GW1A3,
BRCMS_SROM_PA2GW2A0,
BRCMS_SROM_PA2GW2A1,
BRCMS_SROM_PA2GW2A2,
BRCMS_SROM_PA2GW2A3,
BRCMS_SROM_PA5GHW0A0,
BRCMS_SROM_PA5GHW0A1,
BRCMS_SROM_PA5GHW0A2,
BRCMS_SROM_PA5GHW0A3,
BRCMS_SROM_PA5GHW1A0,
BRCMS_SROM_PA5GHW1A1,
BRCMS_SROM_PA5GHW1A2,
BRCMS_SROM_PA5GHW1A3,
BRCMS_SROM_PA5GHW2A0,
BRCMS_SROM_PA5GHW2A1,
BRCMS_SROM_PA5GHW2A2,
BRCMS_SROM_PA5GHW2A3,
BRCMS_SROM_PA5GLW0A0,
BRCMS_SROM_PA5GLW0A1,
BRCMS_SROM_PA5GLW0A2,
BRCMS_SROM_PA5GLW0A3,
BRCMS_SROM_PA5GLW1A0,
BRCMS_SROM_PA5GLW1A1,
BRCMS_SROM_PA5GLW1A2,
BRCMS_SROM_PA5GLW1A3,
BRCMS_SROM_PA5GLW2A0,
BRCMS_SROM_PA5GLW2A1,
BRCMS_SROM_PA5GLW2A2,
BRCMS_SROM_PA5GLW2A3,
BRCMS_SROM_PA5GW0A0,
BRCMS_SROM_PA5GW0A1,
BRCMS_SROM_PA5GW0A2,
BRCMS_SROM_PA5GW0A3,
BRCMS_SROM_PA5GW1A0,
BRCMS_SROM_PA5GW1A1,
BRCMS_SROM_PA5GW1A2,
BRCMS_SROM_PA5GW1A3,
BRCMS_SROM_PA5GW2A0,
BRCMS_SROM_PA5GW2A1,
BRCMS_SROM_PA5GW2A2,
BRCMS_SROM_PA5GW2A3,
};
#define BRCMS_NUMRATES 16 /* max # of rates in a rateset */
/* phy types */
@ -565,8 +339,6 @@ extern void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
struct ieee80211_sta *sta, u16 tid);
extern void brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
u8 ba_wsize, uint max_rx_ampdu_bytes);
extern char *getvar(struct si_pub *sih, enum brcms_srom_id id);
extern int getintvar(struct si_pub *sih, enum brcms_srom_id id);
extern int brcms_c_module_register(struct brcms_pub *pub,
const char *name, struct brcms_info *hdl,
int (*down_fn)(void *handle));

View File

@ -1,980 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#include <linux/kernel.h>
#include <linux/string.h>
#include <linux/io.h>
#include <linux/etherdevice.h>
#include <linux/crc8.h>
#include <stdarg.h>
#include <chipcommon.h>
#include <brcmu_utils.h>
#include "pub.h"
#include "nicpci.h"
#include "aiutils.h"
#include "otp.h"
#include "srom.h"
#include "soc.h"
/*
* SROM CRC8 polynomial value:
*
* x^8 + x^7 +x^6 + x^4 + x^2 + 1
*/
#define SROM_CRC8_POLY 0xAB
/* Maximum srom: 6 Kilobits == 768 bytes */
#define SROM_MAX 768
/* PCI fields */
#define PCI_F0DEVID 48
#define SROM_WORDS 64
#define SROM_SSID 2
#define SROM_WL1LHMAXP 29
#define SROM_WL1LPAB0 30
#define SROM_WL1LPAB1 31
#define SROM_WL1LPAB2 32
#define SROM_WL1HPAB0 33
#define SROM_WL1HPAB1 34
#define SROM_WL1HPAB2 35
#define SROM_MACHI_IL0 36
#define SROM_MACMID_IL0 37
#define SROM_MACLO_IL0 38
#define SROM_MACHI_ET1 42
#define SROM_MACMID_ET1 43
#define SROM_MACLO_ET1 44
#define SROM_BXARSSI2G 40
#define SROM_BXARSSI5G 41
#define SROM_TRI52G 42
#define SROM_TRI5GHL 43
#define SROM_RXPO52G 45
#define SROM_AABREV 46
/* Fields in AABREV */
#define SROM_BR_MASK 0x00ff
#define SROM_CC_MASK 0x0f00
#define SROM_CC_SHIFT 8
#define SROM_AA0_MASK 0x3000
#define SROM_AA0_SHIFT 12
#define SROM_AA1_MASK 0xc000
#define SROM_AA1_SHIFT 14
#define SROM_WL0PAB0 47
#define SROM_WL0PAB1 48
#define SROM_WL0PAB2 49
#define SROM_LEDBH10 50
#define SROM_LEDBH32 51
#define SROM_WL10MAXP 52
#define SROM_WL1PAB0 53
#define SROM_WL1PAB1 54
#define SROM_WL1PAB2 55
#define SROM_ITT 56
#define SROM_BFL 57
#define SROM_BFL2 28
#define SROM_AG10 58
#define SROM_CCODE 59
#define SROM_OPO 60
#define SROM_CRCREV 63
#define SROM4_WORDS 220
#define SROM4_TXCHAIN_MASK 0x000f
#define SROM4_RXCHAIN_MASK 0x00f0
#define SROM4_SWITCH_MASK 0xff00
/* Per-path fields */
#define MAX_PATH_SROM 4
#define SROM4_CRCREV 219
/* SROM Rev 8: Make space for a 48word hardware header for PCIe rev >= 6.
* This is acombined srom for both MIMO and SISO boards, usable in
* the .130 4Kilobit OTP with hardware redundancy.
*/
#define SROM8_BREV 65
#define SROM8_BFL0 66
#define SROM8_BFL1 67
#define SROM8_BFL2 68
#define SROM8_BFL3 69
#define SROM8_MACHI 70
#define SROM8_MACMID 71
#define SROM8_MACLO 72
#define SROM8_CCODE 73
#define SROM8_REGREV 74
#define SROM8_LEDBH10 75
#define SROM8_LEDBH32 76
#define SROM8_LEDDC 77
#define SROM8_AA 78
#define SROM8_AG10 79
#define SROM8_AG32 80
#define SROM8_TXRXC 81
#define SROM8_BXARSSI2G 82
#define SROM8_BXARSSI5G 83
#define SROM8_TRI52G 84
#define SROM8_TRI5GHL 85
#define SROM8_RXPO52G 86
#define SROM8_FEM2G 87
#define SROM8_FEM5G 88
#define SROM8_FEM_ANTSWLUT_MASK 0xf800
#define SROM8_FEM_ANTSWLUT_SHIFT 11
#define SROM8_FEM_TR_ISO_MASK 0x0700
#define SROM8_FEM_TR_ISO_SHIFT 8
#define SROM8_FEM_PDET_RANGE_MASK 0x00f8
#define SROM8_FEM_PDET_RANGE_SHIFT 3
#define SROM8_FEM_EXTPA_GAIN_MASK 0x0006
#define SROM8_FEM_EXTPA_GAIN_SHIFT 1
#define SROM8_FEM_TSSIPOS_MASK 0x0001
#define SROM8_FEM_TSSIPOS_SHIFT 0
#define SROM8_THERMAL 89
/* Temp sense related entries */
#define SROM8_MPWR_RAWTS 90
#define SROM8_TS_SLP_OPT_CORRX 91
/* FOC: freiquency offset correction, HWIQ: H/W IOCAL enable,
* IQSWP: IQ CAL swap disable */
#define SROM8_FOC_HWIQ_IQSWP 92
/* Temperature delta for PHY calibration */
#define SROM8_PHYCAL_TEMPDELTA 93
/* Per-path offsets & fields */
#define SROM8_PATH0 96
#define SROM8_PATH1 112
#define SROM8_PATH2 128
#define SROM8_PATH3 144
#define SROM8_2G_ITT_MAXP 0
#define SROM8_2G_PA 1
#define SROM8_5G_ITT_MAXP 4
#define SROM8_5GLH_MAXP 5
#define SROM8_5G_PA 6
#define SROM8_5GL_PA 9
#define SROM8_5GH_PA 12
/* All the miriad power offsets */
#define SROM8_2G_CCKPO 160
#define SROM8_2G_OFDMPO 161
#define SROM8_5G_OFDMPO 163
#define SROM8_5GL_OFDMPO 165
#define SROM8_5GH_OFDMPO 167
#define SROM8_2G_MCSPO 169
#define SROM8_5G_MCSPO 177
#define SROM8_5GL_MCSPO 185
#define SROM8_5GH_MCSPO 193
#define SROM8_CDDPO 201
#define SROM8_STBCPO 202
#define SROM8_BW40PO 203
#define SROM8_BWDUPPO 204
/* SISO PA parameters are in the path0 spaces */
#define SROM8_SISO 96
/* Legacy names for SISO PA paramters */
#define SROM8_W0_ITTMAXP (SROM8_SISO + SROM8_2G_ITT_MAXP)
#define SROM8_W0_PAB0 (SROM8_SISO + SROM8_2G_PA)
#define SROM8_W0_PAB1 (SROM8_SISO + SROM8_2G_PA + 1)
#define SROM8_W0_PAB2 (SROM8_SISO + SROM8_2G_PA + 2)
#define SROM8_W1_ITTMAXP (SROM8_SISO + SROM8_5G_ITT_MAXP)
#define SROM8_W1_MAXP_LCHC (SROM8_SISO + SROM8_5GLH_MAXP)
#define SROM8_W1_PAB0 (SROM8_SISO + SROM8_5G_PA)
#define SROM8_W1_PAB1 (SROM8_SISO + SROM8_5G_PA + 1)
#define SROM8_W1_PAB2 (SROM8_SISO + SROM8_5G_PA + 2)
#define SROM8_W1_PAB0_LC (SROM8_SISO + SROM8_5GL_PA)
#define SROM8_W1_PAB1_LC (SROM8_SISO + SROM8_5GL_PA + 1)
#define SROM8_W1_PAB2_LC (SROM8_SISO + SROM8_5GL_PA + 2)
#define SROM8_W1_PAB0_HC (SROM8_SISO + SROM8_5GH_PA)
#define SROM8_W1_PAB1_HC (SROM8_SISO + SROM8_5GH_PA + 1)
#define SROM8_W1_PAB2_HC (SROM8_SISO + SROM8_5GH_PA + 2)
/* SROM REV 9 */
#define SROM9_2GPO_CCKBW20 160
#define SROM9_2GPO_CCKBW20UL 161
#define SROM9_2GPO_LOFDMBW20 162
#define SROM9_2GPO_LOFDMBW20UL 164
#define SROM9_5GLPO_LOFDMBW20 166
#define SROM9_5GLPO_LOFDMBW20UL 168
#define SROM9_5GMPO_LOFDMBW20 170
#define SROM9_5GMPO_LOFDMBW20UL 172
#define SROM9_5GHPO_LOFDMBW20 174
#define SROM9_5GHPO_LOFDMBW20UL 176
#define SROM9_2GPO_MCSBW20 178
#define SROM9_2GPO_MCSBW20UL 180
#define SROM9_2GPO_MCSBW40 182
#define SROM9_5GLPO_MCSBW20 184
#define SROM9_5GLPO_MCSBW20UL 186
#define SROM9_5GLPO_MCSBW40 188
#define SROM9_5GMPO_MCSBW20 190
#define SROM9_5GMPO_MCSBW20UL 192
#define SROM9_5GMPO_MCSBW40 194
#define SROM9_5GHPO_MCSBW20 196
#define SROM9_5GHPO_MCSBW20UL 198
#define SROM9_5GHPO_MCSBW40 200
#define SROM9_PO_MCS32 202
#define SROM9_PO_LOFDM40DUP 203
/* SROM flags (see sromvar_t) */
/* value continues as described by the next entry */
#define SRFL_MORE 1
#define SRFL_NOFFS 2 /* value bits can't be all one's */
#define SRFL_PRHEX 4 /* value is in hexdecimal format */
#define SRFL_PRSIGN 8 /* value is in signed decimal format */
#define SRFL_CCODE 0x10 /* value is in country code format */
#define SRFL_ETHADDR 0x20 /* value is an Ethernet address */
#define SRFL_LEDDC 0x40 /* value is an LED duty cycle */
/* do not generate a nvram param, entry is for mfgc */
#define SRFL_NOVAR 0x80
/* Max. nvram variable table size */
#define MAXSZ_NVRAM_VARS 4096
/*
* indicates type of value.
*/
enum brcms_srom_var_type {
BRCMS_SROM_STRING,
BRCMS_SROM_SNUMBER,
BRCMS_SROM_UNUMBER
};
/*
* storage type for srom variable.
*
* var_list: for linked list operations.
* varid: identifier of the variable.
* var_type: type of variable.
* buf: variable value when var_type == BRCMS_SROM_STRING.
* uval: unsigned variable value when var_type == BRCMS_SROM_UNUMBER.
* sval: signed variable value when var_type == BRCMS_SROM_SNUMBER.
*/
struct brcms_srom_list_head {
struct list_head var_list;
enum brcms_srom_id varid;
enum brcms_srom_var_type var_type;
union {
char buf[0];
u32 uval;
s32 sval;
};
};
struct brcms_sromvar {
enum brcms_srom_id varid;
u32 revmask;
u32 flags;
u16 off;
u16 mask;
};
struct brcms_varbuf {
char *base; /* pointer to buffer base */
char *buf; /* pointer to current position */
unsigned int size; /* current (residual) size in bytes */
};
/*
* Assumptions:
* - Ethernet address spans across 3 consecutive words
*
* Table rules:
* - Add multiple entries next to each other if a value spans across multiple
* words (even multiple fields in the same word) with each entry except the
* last having it's SRFL_MORE bit set.
* - Ethernet address entry does not follow above rule and must not have
* SRFL_MORE bit set. Its SRFL_ETHADDR bit implies it takes multiple words.
* - The last entry's name field must be NULL to indicate the end of the table.
* Other entries must have non-NULL name.
*/
static const struct brcms_sromvar pci_sromvars[] = {
{BRCMS_SROM_DEVID, 0xffffff00, SRFL_PRHEX | SRFL_NOVAR, PCI_F0DEVID,
0xffff},
{BRCMS_SROM_BOARDREV, 0xffffff00, SRFL_PRHEX, SROM8_BREV, 0xffff},
{BRCMS_SROM_BOARDFLAGS, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL0,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_BFL1, 0xffff},
{BRCMS_SROM_BOARDFLAGS2, 0xffffff00, SRFL_PRHEX | SRFL_MORE, SROM8_BFL2,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_BFL3, 0xffff},
{BRCMS_SROM_BOARDTYPE, 0xfffffffc, SRFL_PRHEX, SROM_SSID, 0xffff},
{BRCMS_SROM_BOARDNUM, 0xffffff00, 0, SROM8_MACLO, 0xffff},
{BRCMS_SROM_REGREV, 0xffffff00, 0, SROM8_REGREV, 0x00ff},
{BRCMS_SROM_LEDBH0, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0x00ff},
{BRCMS_SROM_LEDBH1, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH10, 0xff00},
{BRCMS_SROM_LEDBH2, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0x00ff},
{BRCMS_SROM_LEDBH3, 0xffffff00, SRFL_NOFFS, SROM8_LEDBH32, 0xff00},
{BRCMS_SROM_PA0B0, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB0, 0xffff},
{BRCMS_SROM_PA0B1, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB1, 0xffff},
{BRCMS_SROM_PA0B2, 0xffffff00, SRFL_PRHEX, SROM8_W0_PAB2, 0xffff},
{BRCMS_SROM_PA0ITSSIT, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0xff00},
{BRCMS_SROM_PA0MAXPWR, 0xffffff00, 0, SROM8_W0_ITTMAXP, 0x00ff},
{BRCMS_SROM_OPO, 0xffffff00, 0, SROM8_2G_OFDMPO, 0x00ff},
{BRCMS_SROM_AA2G, 0xffffff00, 0, SROM8_AA, 0x00ff},
{BRCMS_SROM_AA5G, 0xffffff00, 0, SROM8_AA, 0xff00},
{BRCMS_SROM_AG0, 0xffffff00, 0, SROM8_AG10, 0x00ff},
{BRCMS_SROM_AG1, 0xffffff00, 0, SROM8_AG10, 0xff00},
{BRCMS_SROM_AG2, 0xffffff00, 0, SROM8_AG32, 0x00ff},
{BRCMS_SROM_AG3, 0xffffff00, 0, SROM8_AG32, 0xff00},
{BRCMS_SROM_PA1B0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0, 0xffff},
{BRCMS_SROM_PA1B1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1, 0xffff},
{BRCMS_SROM_PA1B2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2, 0xffff},
{BRCMS_SROM_PA1LOB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_LC, 0xffff},
{BRCMS_SROM_PA1LOB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_LC, 0xffff},
{BRCMS_SROM_PA1LOB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_LC, 0xffff},
{BRCMS_SROM_PA1HIB0, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB0_HC, 0xffff},
{BRCMS_SROM_PA1HIB1, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB1_HC, 0xffff},
{BRCMS_SROM_PA1HIB2, 0xffffff00, SRFL_PRHEX, SROM8_W1_PAB2_HC, 0xffff},
{BRCMS_SROM_PA1ITSSIT, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0xff00},
{BRCMS_SROM_PA1MAXPWR, 0xffffff00, 0, SROM8_W1_ITTMAXP, 0x00ff},
{BRCMS_SROM_PA1LOMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0xff00},
{BRCMS_SROM_PA1HIMAXPWR, 0xffffff00, 0, SROM8_W1_MAXP_LCHC, 0x00ff},
{BRCMS_SROM_BXA2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x1800},
{BRCMS_SROM_RSSISAV2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x0700},
{BRCMS_SROM_RSSISMC2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x00f0},
{BRCMS_SROM_RSSISMF2G, 0xffffff00, 0, SROM8_BXARSSI2G, 0x000f},
{BRCMS_SROM_BXA5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x1800},
{BRCMS_SROM_RSSISAV5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x0700},
{BRCMS_SROM_RSSISMC5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x00f0},
{BRCMS_SROM_RSSISMF5G, 0xffffff00, 0, SROM8_BXARSSI5G, 0x000f},
{BRCMS_SROM_TRI2G, 0xffffff00, 0, SROM8_TRI52G, 0x00ff},
{BRCMS_SROM_TRI5G, 0xffffff00, 0, SROM8_TRI52G, 0xff00},
{BRCMS_SROM_TRI5GL, 0xffffff00, 0, SROM8_TRI5GHL, 0x00ff},
{BRCMS_SROM_TRI5GH, 0xffffff00, 0, SROM8_TRI5GHL, 0xff00},
{BRCMS_SROM_RXPO2G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0x00ff},
{BRCMS_SROM_RXPO5G, 0xffffff00, SRFL_PRSIGN, SROM8_RXPO52G, 0xff00},
{BRCMS_SROM_TXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
SROM4_TXCHAIN_MASK},
{BRCMS_SROM_RXCHAIN, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
SROM4_RXCHAIN_MASK},
{BRCMS_SROM_ANTSWITCH, 0xffffff00, SRFL_NOFFS, SROM8_TXRXC,
SROM4_SWITCH_MASK},
{BRCMS_SROM_TSSIPOS2G, 0xffffff00, 0, SROM8_FEM2G,
SROM8_FEM_TSSIPOS_MASK},
{BRCMS_SROM_EXTPAGAIN2G, 0xffffff00, 0, SROM8_FEM2G,
SROM8_FEM_EXTPA_GAIN_MASK},
{BRCMS_SROM_PDETRANGE2G, 0xffffff00, 0, SROM8_FEM2G,
SROM8_FEM_PDET_RANGE_MASK},
{BRCMS_SROM_TRISO2G, 0xffffff00, 0, SROM8_FEM2G, SROM8_FEM_TR_ISO_MASK},
{BRCMS_SROM_ANTSWCTL2G, 0xffffff00, 0, SROM8_FEM2G,
SROM8_FEM_ANTSWLUT_MASK},
{BRCMS_SROM_TSSIPOS5G, 0xffffff00, 0, SROM8_FEM5G,
SROM8_FEM_TSSIPOS_MASK},
{BRCMS_SROM_EXTPAGAIN5G, 0xffffff00, 0, SROM8_FEM5G,
SROM8_FEM_EXTPA_GAIN_MASK},
{BRCMS_SROM_PDETRANGE5G, 0xffffff00, 0, SROM8_FEM5G,
SROM8_FEM_PDET_RANGE_MASK},
{BRCMS_SROM_TRISO5G, 0xffffff00, 0, SROM8_FEM5G, SROM8_FEM_TR_ISO_MASK},
{BRCMS_SROM_ANTSWCTL5G, 0xffffff00, 0, SROM8_FEM5G,
SROM8_FEM_ANTSWLUT_MASK},
{BRCMS_SROM_TEMPTHRESH, 0xffffff00, 0, SROM8_THERMAL, 0xff00},
{BRCMS_SROM_TEMPOFFSET, 0xffffff00, 0, SROM8_THERMAL, 0x00ff},
{BRCMS_SROM_CCODE, 0xffffff00, SRFL_CCODE, SROM8_CCODE, 0xffff},
{BRCMS_SROM_MACADDR, 0xffffff00, SRFL_ETHADDR, SROM8_MACHI, 0xffff},
{BRCMS_SROM_LEDDC, 0xffffff00, SRFL_NOFFS | SRFL_LEDDC, SROM8_LEDDC,
0xffff},
{BRCMS_SROM_RAWTEMPSENSE, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
0x01ff},
{BRCMS_SROM_MEASPOWER, 0xffffff00, SRFL_PRHEX, SROM8_MPWR_RAWTS,
0xfe00},
{BRCMS_SROM_TEMPSENSE_SLOPE, 0xffffff00, SRFL_PRHEX,
SROM8_TS_SLP_OPT_CORRX, 0x00ff},
{BRCMS_SROM_TEMPCORRX, 0xffffff00, SRFL_PRHEX, SROM8_TS_SLP_OPT_CORRX,
0xfc00},
{BRCMS_SROM_TEMPSENSE_OPTION, 0xffffff00, SRFL_PRHEX,
SROM8_TS_SLP_OPT_CORRX, 0x0300},
{BRCMS_SROM_FREQOFFSET_CORR, 0xffffff00, SRFL_PRHEX,
SROM8_FOC_HWIQ_IQSWP, 0x000f},
{BRCMS_SROM_IQCAL_SWP_DIS, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
0x0010},
{BRCMS_SROM_HW_IQCAL_EN, 0xffffff00, SRFL_PRHEX, SROM8_FOC_HWIQ_IQSWP,
0x0020},
{BRCMS_SROM_PHYCAL_TEMPDELTA, 0xffffff00, 0, SROM8_PHYCAL_TEMPDELTA,
0x00ff},
{BRCMS_SROM_CCK2GPO, 0x00000100, 0, SROM8_2G_CCKPO, 0xffff},
{BRCMS_SROM_OFDM2GPO, 0x00000100, SRFL_MORE, SROM8_2G_OFDMPO, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_2G_OFDMPO + 1, 0xffff},
{BRCMS_SROM_OFDM5GPO, 0x00000100, SRFL_MORE, SROM8_5G_OFDMPO, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_5G_OFDMPO + 1, 0xffff},
{BRCMS_SROM_OFDM5GLPO, 0x00000100, SRFL_MORE, SROM8_5GL_OFDMPO, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_5GL_OFDMPO + 1, 0xffff},
{BRCMS_SROM_OFDM5GHPO, 0x00000100, SRFL_MORE, SROM8_5GH_OFDMPO, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM8_5GH_OFDMPO + 1, 0xffff},
{BRCMS_SROM_MCS2GPO0, 0x00000100, 0, SROM8_2G_MCSPO, 0xffff},
{BRCMS_SROM_MCS2GPO1, 0x00000100, 0, SROM8_2G_MCSPO + 1, 0xffff},
{BRCMS_SROM_MCS2GPO2, 0x00000100, 0, SROM8_2G_MCSPO + 2, 0xffff},
{BRCMS_SROM_MCS2GPO3, 0x00000100, 0, SROM8_2G_MCSPO + 3, 0xffff},
{BRCMS_SROM_MCS2GPO4, 0x00000100, 0, SROM8_2G_MCSPO + 4, 0xffff},
{BRCMS_SROM_MCS2GPO5, 0x00000100, 0, SROM8_2G_MCSPO + 5, 0xffff},
{BRCMS_SROM_MCS2GPO6, 0x00000100, 0, SROM8_2G_MCSPO + 6, 0xffff},
{BRCMS_SROM_MCS2GPO7, 0x00000100, 0, SROM8_2G_MCSPO + 7, 0xffff},
{BRCMS_SROM_MCS5GPO0, 0x00000100, 0, SROM8_5G_MCSPO, 0xffff},
{BRCMS_SROM_MCS5GPO1, 0x00000100, 0, SROM8_5G_MCSPO + 1, 0xffff},
{BRCMS_SROM_MCS5GPO2, 0x00000100, 0, SROM8_5G_MCSPO + 2, 0xffff},
{BRCMS_SROM_MCS5GPO3, 0x00000100, 0, SROM8_5G_MCSPO + 3, 0xffff},
{BRCMS_SROM_MCS5GPO4, 0x00000100, 0, SROM8_5G_MCSPO + 4, 0xffff},
{BRCMS_SROM_MCS5GPO5, 0x00000100, 0, SROM8_5G_MCSPO + 5, 0xffff},
{BRCMS_SROM_MCS5GPO6, 0x00000100, 0, SROM8_5G_MCSPO + 6, 0xffff},
{BRCMS_SROM_MCS5GPO7, 0x00000100, 0, SROM8_5G_MCSPO + 7, 0xffff},
{BRCMS_SROM_MCS5GLPO0, 0x00000100, 0, SROM8_5GL_MCSPO, 0xffff},
{BRCMS_SROM_MCS5GLPO1, 0x00000100, 0, SROM8_5GL_MCSPO + 1, 0xffff},
{BRCMS_SROM_MCS5GLPO2, 0x00000100, 0, SROM8_5GL_MCSPO + 2, 0xffff},
{BRCMS_SROM_MCS5GLPO3, 0x00000100, 0, SROM8_5GL_MCSPO + 3, 0xffff},
{BRCMS_SROM_MCS5GLPO4, 0x00000100, 0, SROM8_5GL_MCSPO + 4, 0xffff},
{BRCMS_SROM_MCS5GLPO5, 0x00000100, 0, SROM8_5GL_MCSPO + 5, 0xffff},
{BRCMS_SROM_MCS5GLPO6, 0x00000100, 0, SROM8_5GL_MCSPO + 6, 0xffff},
{BRCMS_SROM_MCS5GLPO7, 0x00000100, 0, SROM8_5GL_MCSPO + 7, 0xffff},
{BRCMS_SROM_MCS5GHPO0, 0x00000100, 0, SROM8_5GH_MCSPO, 0xffff},
{BRCMS_SROM_MCS5GHPO1, 0x00000100, 0, SROM8_5GH_MCSPO + 1, 0xffff},
{BRCMS_SROM_MCS5GHPO2, 0x00000100, 0, SROM8_5GH_MCSPO + 2, 0xffff},
{BRCMS_SROM_MCS5GHPO3, 0x00000100, 0, SROM8_5GH_MCSPO + 3, 0xffff},
{BRCMS_SROM_MCS5GHPO4, 0x00000100, 0, SROM8_5GH_MCSPO + 4, 0xffff},
{BRCMS_SROM_MCS5GHPO5, 0x00000100, 0, SROM8_5GH_MCSPO + 5, 0xffff},
{BRCMS_SROM_MCS5GHPO6, 0x00000100, 0, SROM8_5GH_MCSPO + 6, 0xffff},
{BRCMS_SROM_MCS5GHPO7, 0x00000100, 0, SROM8_5GH_MCSPO + 7, 0xffff},
{BRCMS_SROM_CDDPO, 0x00000100, 0, SROM8_CDDPO, 0xffff},
{BRCMS_SROM_STBCPO, 0x00000100, 0, SROM8_STBCPO, 0xffff},
{BRCMS_SROM_BW40PO, 0x00000100, 0, SROM8_BW40PO, 0xffff},
{BRCMS_SROM_BWDUPPO, 0x00000100, 0, SROM8_BWDUPPO, 0xffff},
/* power per rate from sromrev 9 */
{BRCMS_SROM_CCKBW202GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20, 0xffff},
{BRCMS_SROM_CCKBW20UL2GPO, 0xfffffe00, 0, SROM9_2GPO_CCKBW20UL, 0xffff},
{BRCMS_SROM_LEGOFDMBW202GPO, 0xfffffe00, SRFL_MORE,
SROM9_2GPO_LOFDMBW20, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20 + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW20UL2GPO, 0xfffffe00, SRFL_MORE,
SROM9_2GPO_LOFDMBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_LOFDMBW20UL + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW205GLPO, 0xfffffe00, SRFL_MORE,
SROM9_5GLPO_LOFDMBW20, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20 + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
SROM9_5GLPO_LOFDMBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_LOFDMBW20UL + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW205GMPO, 0xfffffe00, SRFL_MORE,
SROM9_5GMPO_LOFDMBW20, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20 + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
SROM9_5GMPO_LOFDMBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_LOFDMBW20UL + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW205GHPO, 0xfffffe00, SRFL_MORE,
SROM9_5GHPO_LOFDMBW20, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20 + 1, 0xffff},
{BRCMS_SROM_LEGOFDMBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
SROM9_5GHPO_LOFDMBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_LOFDMBW20UL + 1, 0xffff},
{BRCMS_SROM_MCSBW202GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20 + 1, 0xffff},
{BRCMS_SROM_MCSBW20UL2GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW20UL,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW20UL + 1, 0xffff},
{BRCMS_SROM_MCSBW402GPO, 0xfffffe00, SRFL_MORE, SROM9_2GPO_MCSBW40,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_2GPO_MCSBW40 + 1, 0xffff},
{BRCMS_SROM_MCSBW205GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW20,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20 + 1, 0xffff},
{BRCMS_SROM_MCSBW20UL5GLPO, 0xfffffe00, SRFL_MORE,
SROM9_5GLPO_MCSBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW20UL + 1, 0xffff},
{BRCMS_SROM_MCSBW405GLPO, 0xfffffe00, SRFL_MORE, SROM9_5GLPO_MCSBW40,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GLPO_MCSBW40 + 1, 0xffff},
{BRCMS_SROM_MCSBW205GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW20,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20 + 1, 0xffff},
{BRCMS_SROM_MCSBW20UL5GMPO, 0xfffffe00, SRFL_MORE,
SROM9_5GMPO_MCSBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW20UL + 1, 0xffff},
{BRCMS_SROM_MCSBW405GMPO, 0xfffffe00, SRFL_MORE, SROM9_5GMPO_MCSBW40,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GMPO_MCSBW40 + 1, 0xffff},
{BRCMS_SROM_MCSBW205GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW20,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20 + 1, 0xffff},
{BRCMS_SROM_MCSBW20UL5GHPO, 0xfffffe00, SRFL_MORE,
SROM9_5GHPO_MCSBW20UL, 0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW20UL + 1, 0xffff},
{BRCMS_SROM_MCSBW405GHPO, 0xfffffe00, SRFL_MORE, SROM9_5GHPO_MCSBW40,
0xffff},
{BRCMS_SROM_CONT, 0, 0, SROM9_5GHPO_MCSBW40 + 1, 0xffff},
{BRCMS_SROM_MCS32PO, 0xfffffe00, 0, SROM9_PO_MCS32, 0xffff},
{BRCMS_SROM_LEGOFDM40DUPPO, 0xfffffe00, 0, SROM9_PO_LOFDM40DUP, 0xffff},
{BRCMS_SROM_NULL, 0, 0, 0, 0}
};
static const struct brcms_sromvar perpath_pci_sromvars[] = {
{BRCMS_SROM_MAXP2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0x00ff},
{BRCMS_SROM_ITT2GA0, 0xffffff00, 0, SROM8_2G_ITT_MAXP, 0xff00},
{BRCMS_SROM_ITT5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0xff00},
{BRCMS_SROM_PA2GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA, 0xffff},
{BRCMS_SROM_PA2GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 1, 0xffff},
{BRCMS_SROM_PA2GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_2G_PA + 2, 0xffff},
{BRCMS_SROM_MAXP5GA0, 0xffffff00, 0, SROM8_5G_ITT_MAXP, 0x00ff},
{BRCMS_SROM_MAXP5GHA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0x00ff},
{BRCMS_SROM_MAXP5GLA0, 0xffffff00, 0, SROM8_5GLH_MAXP, 0xff00},
{BRCMS_SROM_PA5GW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA, 0xffff},
{BRCMS_SROM_PA5GW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 1, 0xffff},
{BRCMS_SROM_PA5GW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5G_PA + 2, 0xffff},
{BRCMS_SROM_PA5GLW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA, 0xffff},
{BRCMS_SROM_PA5GLW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 1,
0xffff},
{BRCMS_SROM_PA5GLW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GL_PA + 2,
0xffff},
{BRCMS_SROM_PA5GHW0A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA, 0xffff},
{BRCMS_SROM_PA5GHW1A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 1,
0xffff},
{BRCMS_SROM_PA5GHW2A0, 0xffffff00, SRFL_PRHEX, SROM8_5GH_PA + 2,
0xffff},
{BRCMS_SROM_NULL, 0, 0, 0, 0}
};
/* crc table has the same contents for every device instance, so it can be
* shared between devices. */
static u8 brcms_srom_crc8_table[CRC8_TABLE_SIZE];
static uint mask_shift(u16 mask)
{
uint i;
for (i = 0; i < (sizeof(mask) << 3); i++) {
if (mask & (1 << i))
return i;
}
return 0;
}
static uint mask_width(u16 mask)
{
int i;
for (i = (sizeof(mask) << 3) - 1; i >= 0; i--) {
if (mask & (1 << i))
return (uint) (i - mask_shift(mask) + 1);
}
return 0;
}
static inline void le16_to_cpu_buf(u16 *buf, uint nwords)
{
while (nwords--)
*(buf + nwords) = le16_to_cpu(*(__le16 *)(buf + nwords));
}
static inline void cpu_to_le16_buf(u16 *buf, uint nwords)
{
while (nwords--)
*(__le16 *)(buf + nwords) = cpu_to_le16(*(buf + nwords));
}
/*
* convert binary srom data into linked list of srom variable items.
*/
static int
_initvars_srom_pci(u8 sromrev, u16 *srom, struct list_head *var_list)
{
struct brcms_srom_list_head *entry;
enum brcms_srom_id id;
u16 w;
u32 val = 0;
const struct brcms_sromvar *srv;
uint width;
uint flags;
u32 sr = (1 << sromrev);
uint p;
uint pb = SROM8_PATH0;
const uint psz = SROM8_PATH1 - SROM8_PATH0;
/* first store the srom revision */
entry = kzalloc(sizeof(struct brcms_srom_list_head), GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->varid = BRCMS_SROM_REV;
entry->var_type = BRCMS_SROM_UNUMBER;
entry->uval = sromrev;
list_add(&entry->var_list, var_list);
for (srv = pci_sromvars; srv->varid != BRCMS_SROM_NULL; srv++) {
enum brcms_srom_var_type type;
u8 ea[ETH_ALEN];
u8 extra_space = 0;
if ((srv->revmask & sr) == 0)
continue;
flags = srv->flags;
id = srv->varid;
/* This entry is for mfgc only. Don't generate param for it, */
if (flags & SRFL_NOVAR)
continue;
if (flags & SRFL_ETHADDR) {
/*
* stored in string format XX:XX:XX:XX:XX:XX (17 chars)
*/
ea[0] = (srom[srv->off] >> 8) & 0xff;
ea[1] = srom[srv->off] & 0xff;
ea[2] = (srom[srv->off + 1] >> 8) & 0xff;
ea[3] = srom[srv->off + 1] & 0xff;
ea[4] = (srom[srv->off + 2] >> 8) & 0xff;
ea[5] = srom[srv->off + 2] & 0xff;
/* 17 characters + string terminator - union size */
extra_space = 18 - sizeof(s32);
type = BRCMS_SROM_STRING;
} else {
w = srom[srv->off];
val = (w & srv->mask) >> mask_shift(srv->mask);
width = mask_width(srv->mask);
while (srv->flags & SRFL_MORE) {
srv++;
if (srv->off == 0)
continue;
w = srom[srv->off];
val +=
((w & srv->mask) >> mask_shift(srv->
mask)) <<
width;
width += mask_width(srv->mask);
}
if ((flags & SRFL_NOFFS)
&& ((int)val == (1 << width) - 1))
continue;
if (flags & SRFL_CCODE) {
type = BRCMS_SROM_STRING;
} else if (flags & SRFL_LEDDC) {
/* LED Powersave duty cycle has to be scaled:
*(oncount >> 24) (offcount >> 8)
*/
u32 w32 = /* oncount */
(((val >> 8) & 0xff) << 24) |
/* offcount */
(((val & 0xff)) << 8);
type = BRCMS_SROM_UNUMBER;
val = w32;
} else if ((flags & SRFL_PRSIGN)
&& (val & (1 << (width - 1)))) {
type = BRCMS_SROM_SNUMBER;
val |= ~0 << width;
} else
type = BRCMS_SROM_UNUMBER;
}
entry = kzalloc(sizeof(struct brcms_srom_list_head) +
extra_space, GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->varid = id;
entry->var_type = type;
if (flags & SRFL_ETHADDR) {
snprintf(entry->buf, 18, "%pM", ea);
} else if (flags & SRFL_CCODE) {
if (val == 0)
entry->buf[0] = '\0';
else
snprintf(entry->buf, 3, "%c%c",
(val >> 8), (val & 0xff));
} else {
entry->uval = val;
}
list_add(&entry->var_list, var_list);
}
for (p = 0; p < MAX_PATH_SROM; p++) {
for (srv = perpath_pci_sromvars;
srv->varid != BRCMS_SROM_NULL; srv++) {
if ((srv->revmask & sr) == 0)
continue;
if (srv->flags & SRFL_NOVAR)
continue;
w = srom[pb + srv->off];
val = (w & srv->mask) >> mask_shift(srv->mask);
width = mask_width(srv->mask);
/* Cheating: no per-path var is more than
* 1 word */
if ((srv->flags & SRFL_NOFFS)
&& ((int)val == (1 << width) - 1))
continue;
entry =
kzalloc(sizeof(struct brcms_srom_list_head),
GFP_KERNEL);
if (!entry)
return -ENOMEM;
entry->varid = srv->varid+p;
entry->var_type = BRCMS_SROM_UNUMBER;
entry->uval = val;
list_add(&entry->var_list, var_list);
}
pb += psz;
}
return 0;
}
/*
* The crc check is done on a little-endian array, we need
* to switch the bytes around before checking crc (and
* then switch it back).
*/
static int do_crc_check(u16 *buf, unsigned nwords)
{
u8 crc;
cpu_to_le16_buf(buf, nwords);
crc = crc8(brcms_srom_crc8_table, (void *)buf, nwords << 1, CRC8_INIT_VALUE);
le16_to_cpu_buf(buf, nwords);
return crc == CRC8_GOOD_VALUE(brcms_srom_crc8_table);
}
/*
* Read in and validate sprom.
* Return 0 on success, nonzero on error.
*/
static int
sprom_read_pci(struct si_pub *sih, u16 *buf, uint nwords, bool check_crc)
{
int err = 0;
uint i;
struct bcma_device *core;
uint sprom_offset;
/* determine core to read */
if (ai_get_ccrev(sih) < 32) {
core = ai_findcore(sih, BCMA_CORE_80211, 0);
sprom_offset = PCI_BAR0_SPROM_OFFSET;
} else {
core = ai_findcore(sih, BCMA_CORE_CHIPCOMMON, 0);
sprom_offset = CHIPCREGOFFS(sromotp);
}
/* read the sprom */
for (i = 0; i < nwords; i++)
buf[i] = bcma_read16(core, sprom_offset+i*2);
if (buf[0] == 0xffff)
/*
* The hardware thinks that an srom that starts with
* 0xffff is blank, regardless of the rest of the
* content, so declare it bad.
*/
return -ENODATA;
if (check_crc && !do_crc_check(buf, nwords))
err = -EIO;
return err;
}
static int otp_read_pci(struct si_pub *sih, u16 *buf, uint nwords)
{
u8 *otp;
uint sz = OTP_SZ_MAX / 2; /* size in words */
int err = 0;
otp = kzalloc(OTP_SZ_MAX, GFP_ATOMIC);
if (otp == NULL)
return -ENOMEM;
err = otp_read_region(sih, OTP_HW_RGN, (u16 *) otp, &sz);
sz = min_t(uint, sz, nwords);
memcpy(buf, otp, sz * 2);
kfree(otp);
/* Check CRC */
if (buf[0] == 0xffff)
/* The hardware thinks that an srom that starts with 0xffff
* is blank, regardless of the rest of the content, so declare
* it bad.
*/
return -ENODATA;
/* fixup the endianness so crc8 will pass */
cpu_to_le16_buf(buf, sz);
if (crc8(brcms_srom_crc8_table, (u8 *) buf, sz * 2,
CRC8_INIT_VALUE) != CRC8_GOOD_VALUE(brcms_srom_crc8_table))
err = -EIO;
else
/* now correct the endianness of the byte array */
le16_to_cpu_buf(buf, sz);
return err;
}
/*
* Initialize nonvolatile variable table from sprom.
* Return 0 on success, nonzero on error.
*/
int srom_var_init(struct si_pub *sih)
{
u16 *srom;
u8 sromrev = 0;
u32 sr;
int err = 0;
/*
* Apply CRC over SROM content regardless SROM is present or not.
*/
srom = kmalloc(SROM_MAX, GFP_ATOMIC);
if (!srom)
return -ENOMEM;
crc8_populate_lsb(brcms_srom_crc8_table, SROM_CRC8_POLY);
if (ai_is_sprom_available(sih)) {
err = sprom_read_pci(sih, srom, SROM4_WORDS, true);
if (err == 0)
/* srom read and passed crc */
/* top word of sprom contains version and crc8 */
sromrev = srom[SROM4_CRCREV] & 0xff;
} else {
/* Use OTP if SPROM not available */
err = otp_read_pci(sih, srom, SROM4_WORDS);
if (err == 0)
/* OTP only contain SROM rev8/rev9 for now */
sromrev = srom[SROM4_CRCREV] & 0xff;
}
if (!err) {
struct si_info *sii = (struct si_info *)sih;
/* Bitmask for the sromrev */
sr = 1 << sromrev;
/*
* srom version check: Current valid versions: 8, 9
*/
if ((sr & 0x300) == 0) {
err = -EINVAL;
goto errout;
}
INIT_LIST_HEAD(&sii->var_list);
/* parse SROM into name=value pairs. */
err = _initvars_srom_pci(sromrev, srom, &sii->var_list);
if (err)
srom_free_vars(sih);
}
errout:
kfree(srom);
return err;
}
void srom_free_vars(struct si_pub *sih)
{
struct si_info *sii;
struct brcms_srom_list_head *entry, *next;
sii = (struct si_info *)sih;
list_for_each_entry_safe(entry, next, &sii->var_list, var_list) {
list_del(&entry->var_list);
kfree(entry);
}
}
/*
* Search the name=value vars for a specific one and return its value.
* Returns NULL if not found.
*/
char *getvar(struct si_pub *sih, enum brcms_srom_id id)
{
struct si_info *sii;
struct brcms_srom_list_head *entry;
sii = (struct si_info *)sih;
list_for_each_entry(entry, &sii->var_list, var_list)
if (entry->varid == id)
return &entry->buf[0];
/* nothing found */
return NULL;
}
/*
* Search the vars for a specific one and return its value as
* an integer. Returns 0 if not found.-
*/
int getintvar(struct si_pub *sih, enum brcms_srom_id id)
{
struct si_info *sii;
struct brcms_srom_list_head *entry;
unsigned long res;
sii = (struct si_info *)sih;
list_for_each_entry(entry, &sii->var_list, var_list)
if (entry->varid == id) {
if (entry->var_type == BRCMS_SROM_SNUMBER ||
entry->var_type == BRCMS_SROM_UNUMBER)
return (int)entry->sval;
else if (!kstrtoul(&entry->buf[0], 0, &res))
return (int)res;
}
return 0;
}

View File

@ -1,29 +0,0 @@
/*
* Copyright (c) 2010 Broadcom Corporation
*
* Permission to use, copy, modify, and/or distribute this software for any
* purpose with or without fee is hereby granted, provided that the above
* copyright notice and this permission notice appear in all copies.
*
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
* SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
* OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
#ifndef _BRCM_SROM_H_
#define _BRCM_SROM_H_
#include "types.h"
/* Prototypes */
extern int srom_var_init(struct si_pub *sih);
extern void srom_free_vars(struct si_pub *sih);
extern int srom_read(struct si_pub *sih, uint bus, void *curmap,
uint byteoff, uint nbytes, u16 *buf, bool check_crc);
#endif /* _BRCM_SROM_H_ */

View File

@ -370,9 +370,11 @@ void brcms_c_stf_phy_txant_upd(struct brcms_c_info *wlc)
void brcms_c_stf_phy_chain_calc(struct brcms_c_info *wlc)
{
struct ssb_sprom *sprom = &wlc->hw->d11core->bus->sprom;
/* get available rx/tx chains */
wlc->stf->hw_txchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_TXCHAIN);
wlc->stf->hw_rxchain = (u8) getintvar(wlc->hw->sih, BRCMS_SROM_RXCHAIN);
wlc->stf->hw_txchain = sprom->txchain;
wlc->stf->hw_rxchain = sprom->rxchain;
/* these parameter are intended to be used for all PHY types */
if (wlc->stf->hw_txchain == 0 || wlc->stf->hw_txchain == 0xf) {

View File

@ -31,6 +31,7 @@
#include <linux/module.h>
#include <linux/init.h>
#include <linux/sched.h>
#include <net/mac80211.h>
#include "iwl-dev.h"
#include "iwl-io.h"
@ -273,9 +274,20 @@ void iwlagn_send_advance_bt_config(struct iwl_priv *priv)
return;
}
/*
* Possible situations when BT needs to take over for receive,
* at the same time where STA needs to response to AP's frame(s),
* reduce the tx power of the required response frames, by that,
* allow the concurrent BT receive & WiFi transmit
* (BT - ANT A, WiFi -ANT B), without interference to one another
*
* Reduced tx power apply to control frames only (ACK/Back/CTS)
* when indicated by the BT config command
*/
basic.kill_ack_mask = priv->kill_ack_mask;
basic.kill_cts_mask = priv->kill_cts_mask;
basic.reduce_txpower = priv->reduced_txpower;
if (priv->reduced_txpower)
basic.reduce_txpower = IWLAGN_BT_REDUCED_TX_PWR;
basic.valid = priv->bt_valid;
/*
@ -589,13 +601,31 @@ static bool iwlagn_set_kill_msk(struct iwl_priv *priv,
return need_update;
}
/*
* Upon RSSI changes, sends a bt config command with following changes
* 1. enable/disable "reduced control frames tx power
* 2. update the "kill)ack_mask" and "kill_cts_mask"
*
* If "reduced tx power" is enabled, uCode shall
* 1. ACK/Back/CTS rate shall reduced to 6Mbps
* 2. not use duplciate 20/40MHz mode
*/
static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
struct iwl_bt_uart_msg *uart_msg)
{
bool need_update = false;
struct iwl_rxon_context *ctx = &priv->contexts[IWL_RXON_CTX_BSS];
int ave_rssi;
ave_rssi = ieee80211_ave_rssi(ctx->vif);
if (!ave_rssi) {
/* no rssi data, no changes to reduce tx power */
IWL_DEBUG_COEX(priv, "no rssi data available\n");
return need_update;
}
if (!priv->reduced_txpower &&
!iwl_is_associated(priv, IWL_RXON_CTX_PAN) &&
(ave_rssi > BT_ENABLE_REDUCED_TXPOWER_THRESHOLD) &&
(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
BT_UART_MSG_FRAME3OBEX_MSK)) &&
!(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
@ -606,13 +636,14 @@ static bool iwlagn_fill_txpower_mode(struct iwl_priv *priv,
need_update = true;
} else if (priv->reduced_txpower &&
(iwl_is_associated(priv, IWL_RXON_CTX_PAN) ||
(ave_rssi < BT_DISABLE_REDUCED_TXPOWER_THRESHOLD) ||
(uart_msg->frame3 & (BT_UART_MSG_FRAME3SCOESCO_MSK |
BT_UART_MSG_FRAME3SNIFF_MSK | BT_UART_MSG_FRAME3A2DP_MSK)) ||
!(uart_msg->frame3 & (BT_UART_MSG_FRAME3ACL_MSK |
BT_UART_MSG_FRAME3OBEX_MSK)))) {
/* disable reduced tx power */
priv->reduced_txpower = false;
priv->bt_valid &= ~IWLAGN_BT_VALID_REDUCED_TX_PWR;
priv->bt_valid |= IWLAGN_BT_VALID_REDUCED_TX_PWR;
need_update = true;
}

View File

@ -61,6 +61,10 @@ void iwl_connection_init_rx_config(struct iwl_priv *priv,
RXON_FILTER_ACCEPT_GRP_MSK;
break;
case NL80211_IFTYPE_MONITOR:
ctx->staging.dev_type = RXON_DEV_TYPE_SNIFFER;
break;
default:
IWL_ERR(priv, "Unsupported interface type %d\n",
ctx->vif->type);

View File

@ -590,11 +590,17 @@ turn_off:
spin_unlock_bh(&priv->sta_lock);
if (test_bit(txq_id, priv->agg_q_alloc)) {
/* If the transport didn't know that we wanted to start
* agreggation, don't tell it that we want to stop them
/*
* If the transport didn't know that we wanted to start
* agreggation, don't tell it that we want to stop them.
* This can happen when we don't get the addBA response on
* time, or we hadn't time to drain the AC queues.
*/
if (agg_state != IWL_AGG_STARTING)
if (agg_state == IWL_AGG_ON)
iwl_trans_tx_agg_disable(priv->trans, txq_id);
else
IWL_DEBUG_TX_QUEUES(priv, "Don't disable tx agg: %d\n",
agg_state);
iwlagn_dealloc_agg_txq(priv, txq_id);
}
@ -1300,10 +1306,11 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
(u8 *) &ba_resp->sta_addr_lo32,
ba_resp->sta_id);
IWL_DEBUG_TX_REPLY(priv, "TID = %d, SeqCtl = %d, bitmap = 0x%llx, "
"scd_flow = %d, scd_ssn = %d\n",
"scd_flow = %d, scd_ssn = %d sent:%d, acked:%d\n",
ba_resp->tid, le16_to_cpu(ba_resp->seq_ctl),
(unsigned long long)le64_to_cpu(ba_resp->bitmap),
scd_flow, ba_resp_scd_ssn);
scd_flow, ba_resp_scd_ssn, ba_resp->txed,
ba_resp->txed_2_done);
/* Mark that the expected block-ack response arrived */
agg->wait_for_ba = false;
@ -1319,8 +1326,6 @@ int iwlagn_rx_reply_compressed_ba(struct iwl_priv *priv,
*/
ba_resp->txed = ba_resp->txed_2_done;
}
IWL_DEBUG_HT(priv, "agg frames sent:%d, acked:%d\n",
ba_resp->txed, ba_resp->txed_2_done);
priv->tid_data[sta_id][tid].next_reclaimed = ba_resp_scd_ssn;

View File

@ -603,7 +603,7 @@ void iwl_init_context(struct iwl_priv *priv, u32 ucode_flags)
priv->contexts[IWL_RXON_CTX_BSS].wep_key_cmd = REPLY_WEPKEY;
priv->contexts[IWL_RXON_CTX_BSS].bcast_sta_id = IWLAGN_BROADCAST_ID;
priv->contexts[IWL_RXON_CTX_BSS].exclusive_interface_modes =
BIT(NL80211_IFTYPE_ADHOC);
BIT(NL80211_IFTYPE_ADHOC) | BIT(NL80211_IFTYPE_MONITOR);
priv->contexts[IWL_RXON_CTX_BSS].interface_modes =
BIT(NL80211_IFTYPE_STATION);
priv->contexts[IWL_RXON_CTX_BSS].ap_devtype = RXON_DEV_TYPE_AP;

View File

@ -1910,6 +1910,8 @@ enum iwl_bt_kill_idx {
IWLAGN_BT_VALID_REDUCED_TX_PWR | \
IWLAGN_BT_VALID_3W_LUT)
#define IWLAGN_BT_REDUCED_TX_PWR BIT(0)
#define IWLAGN_BT_DECISION_LUT_SIZE 12
struct iwl_basic_bt_cmd {
@ -1923,6 +1925,10 @@ struct iwl_basic_bt_cmd {
u8 bt3_timer_t2_value;
__le16 bt4_reaction_time; /* unused */
__le32 bt3_lookup_table[IWLAGN_BT_DECISION_LUT_SIZE];
/*
* bit 0: use reduced tx power for control frame
* bit 1 - 7: reserved
*/
u8 reduce_txpower;
u8 reserved;
__le16 valid;
@ -2272,7 +2278,6 @@ struct iwl_ssid_ie {
#define IWL_GOOD_CRC_TH_DISABLED 0
#define IWL_GOOD_CRC_TH_DEFAULT cpu_to_le16(1)
#define IWL_GOOD_CRC_TH_NEVER cpu_to_le16(0xffff)
#define IWL_MAX_SCAN_SIZE 1024
#define IWL_MAX_CMD_SIZE 4096
/*

View File

@ -150,6 +150,7 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
IEEE80211_HW_QUEUE_CONTROL |
IEEE80211_HW_SUPPORTS_PS |
IEEE80211_HW_SUPPORTS_DYNAMIC_PS |
IEEE80211_HW_WANT_MONITOR_VIF |
IEEE80211_HW_SCAN_WHILE_IDLE;
hw->offchannel_tx_hw_queue = IWL_AUX_QUEUE;
@ -223,8 +224,8 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
hw->wiphy->flags &= ~WIPHY_FLAG_PS_ON_BY_DEFAULT;
hw->wiphy->max_scan_ssids = PROBE_OPTION_MAX;
/* we create the 802.11 header and a zero-length SSID element */
hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 2;
/* we create the 802.11 header and a max-length SSID element */
hw->wiphy->max_scan_ie_len = capa->max_probe_length - 24 - 34;
/*
* We don't use all queues: 4 and 9 are unused and any

View File

@ -253,6 +253,8 @@ static void iwl_static_sleep_cmd(struct iwl_priv *priv,
IWL_DEBUG_POWER(priv, "numSkipDtim = %u, dtimPeriod = %d\n",
skip, period);
/* The power level here is 0-4 (used as array index), but user expects
to see 1-5 (according to spec). */
IWL_DEBUG_POWER(priv, "Sleep command for index %d\n", lvl + 1);
}
@ -308,10 +310,12 @@ static void iwl_power_build_cmd(struct iwl_priv *priv,
priv->power_data.debug_sleep_level_override,
dtimper);
else {
/* Note that the user parameter is 1-5 (according to spec),
but we pass 0-4 because it acts as an array index. */
if (iwlwifi_mod_params.power_level > IWL_POWER_INDEX_1 &&
iwlwifi_mod_params.power_level <= IWL_POWER_INDEX_5)
iwlwifi_mod_params.power_level <= IWL_POWER_NUM)
iwl_static_sleep_cmd(priv, cmd,
iwlwifi_mod_params.power_level, dtimper);
iwlwifi_mod_params.power_level - 1, dtimper);
else
iwl_static_sleep_cmd(priv, cmd,
IWL_POWER_INDEX_1, dtimper);

View File

@ -52,6 +52,7 @@
#define IWL_PASSIVE_DWELL_TIME_52 (10)
#define IWL_PASSIVE_DWELL_BASE (100)
#define IWL_CHANNEL_TUNE_TIME 5
#define MAX_SCAN_CHANNEL 50
static int iwl_send_scan_abort(struct iwl_priv *priv)
{
@ -616,7 +617,8 @@ static int iwl_get_channels_for_scan(struct iwl_priv *priv,
*/
static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
const u8 *ies, int ie_len, int left)
const u8 *ies, int ie_len, const u8 *ssid,
u8 ssid_len, int left)
{
int len = 0;
u8 *pos = NULL;
@ -638,14 +640,18 @@ static u16 iwl_fill_probe_req(struct ieee80211_mgmt *frame, const u8 *ta,
/* ...next IE... */
pos = &frame->u.probe_req.variable[0];
/* fill in our indirect SSID IE */
left -= 2;
/* fill in our SSID IE */
left -= ssid_len + 2;
if (left < 0)
return 0;
*pos++ = WLAN_EID_SSID;
*pos++ = 0;
*pos++ = ssid_len;
if (ssid && ssid_len) {
memcpy(pos, ssid, ssid_len);
pos += ssid_len;
}
len += 2;
len += ssid_len + 2;
if (WARN_ON(left < ie_len))
return len;
@ -679,6 +685,15 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
u8 active_chains;
u8 scan_tx_antennas = priv->hw_params.valid_tx_ant;
int ret;
int scan_cmd_size = sizeof(struct iwl_scan_cmd) +
MAX_SCAN_CHANNEL * sizeof(struct iwl_scan_channel) +
priv->fw->ucode_capa.max_probe_length;
const u8 *ssid = NULL;
u8 ssid_len = 0;
if (WARN_ON_ONCE(priv->scan_request &&
priv->scan_request->n_channels > MAX_SCAN_CHANNEL))
return -EINVAL;
lockdep_assert_held(&priv->mutex);
@ -686,8 +701,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
ctx = iwl_rxon_ctx_from_vif(vif);
if (!priv->scan_cmd) {
priv->scan_cmd = kmalloc(sizeof(struct iwl_scan_cmd) +
IWL_MAX_SCAN_SIZE, GFP_KERNEL);
priv->scan_cmd = kmalloc(scan_cmd_size, GFP_KERNEL);
if (!priv->scan_cmd) {
IWL_DEBUG_SCAN(priv,
"fail to allocate memory for scan\n");
@ -695,7 +709,7 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
}
}
scan = priv->scan_cmd;
memset(scan, 0, sizeof(struct iwl_scan_cmd) + IWL_MAX_SCAN_SIZE);
memset(scan, 0, scan_cmd_size);
scan->quiet_plcp_th = IWL_PLCP_QUIET_THRESH;
scan->quiet_time = IWL_ACTIVE_QUIET_TIME;
@ -746,10 +760,18 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
if (priv->scan_request->n_ssids) {
int i, p = 0;
IWL_DEBUG_SCAN(priv, "Kicking off active scan\n");
for (i = 0; i < priv->scan_request->n_ssids; i++) {
/* always does wildcard anyway */
if (!priv->scan_request->ssids[i].ssid_len)
continue;
/*
* The highest priority SSID is inserted to the
* probe request template.
*/
ssid_len = priv->scan_request->ssids[0].ssid_len;
ssid = priv->scan_request->ssids[0].ssid;
/*
* Invert the order of ssids, the firmware will invert
* it back.
*/
for (i = priv->scan_request->n_ssids - 1; i >= 1; i--) {
scan->direct_scan[p].id = WLAN_EID_SSID;
scan->direct_scan[p].len =
priv->scan_request->ssids[i].ssid_len;
@ -883,7 +905,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
vif->addr,
priv->scan_request->ie,
priv->scan_request->ie_len,
IWL_MAX_SCAN_SIZE - sizeof(*scan));
ssid, ssid_len,
scan_cmd_size - sizeof(*scan));
break;
case IWL_SCAN_RADIO_RESET:
case IWL_SCAN_ROC:
@ -891,7 +914,8 @@ static int iwlagn_request_scan(struct iwl_priv *priv, struct ieee80211_vif *vif)
cmd_len = iwl_fill_probe_req(
(struct ieee80211_mgmt *)scan->data,
iwl_bcast_addr, NULL, 0,
IWL_MAX_SCAN_SIZE - sizeof(*scan));
NULL, 0,
scan_cmd_size - sizeof(*scan));
break;
default:
BUG();

View File

@ -746,6 +746,11 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
hwsim_check_sta_magic(txi->control.sta);
ieee80211_tx_info_clear_status(txi);
/* frame was transmitted at most favorable rate at first attempt */
txi->control.rates[0].count = 1;
txi->control.rates[1].idx = -1;
if (!(txi->flags & IEEE80211_TX_CTL_NO_ACK) && ack)
txi->flags |= IEEE80211_TX_STAT_ACK;
ieee80211_tx_status_irqsafe(hw, skb);

View File

@ -29,6 +29,8 @@ mwifiex-y += scan.o
mwifiex-y += join.o
mwifiex-y += sta_ioctl.o
mwifiex-y += sta_cmd.o
mwifiex-y += uap_cmd.o
mwifiex-y += ie.o
mwifiex-y += sta_cmdresp.o
mwifiex-y += sta_event.o
mwifiex-y += sta_tx.o

View File

@ -20,6 +20,23 @@
#include "cfg80211.h"
#include "main.h"
static const struct ieee80211_iface_limit mwifiex_ap_sta_limits[] = {
{
.max = 1, .types = BIT(NL80211_IFTYPE_STATION),
},
{
.max = 1, .types = BIT(NL80211_IFTYPE_AP),
},
};
static const struct ieee80211_iface_combination mwifiex_iface_comb_ap_sta = {
.limits = mwifiex_ap_sta_limits,
.num_different_channels = 1,
.n_limits = ARRAY_SIZE(mwifiex_ap_sta_limits),
.max_interfaces = MWIFIEX_MAX_BSS_NUM,
.beacon_int_infra_match = true,
};
/*
* This function maps the nl802.11 channel type into driver channel type.
*
@ -67,7 +84,7 @@ mwifiex_is_alg_wep(u32 cipher)
/*
* This function retrieves the private structure from kernel wiphy structure.
*/
static void *mwifiex_cfg80211_get_priv(struct wiphy *wiphy)
static void *mwifiex_cfg80211_get_adapter(struct wiphy *wiphy)
{
return (void *) (*(unsigned long *) wiphy_priv(wiphy));
}
@ -80,8 +97,10 @@ mwifiex_cfg80211_del_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
if (mwifiex_set_encode(priv, NULL, 0, key_index, 1)) {
if (mwifiex_set_encode(priv, NULL, 0, key_index, peer_mac, 1)) {
wiphy_err(wiphy, "deleting the crypto keys\n");
return -EFAULT;
}
@ -98,7 +117,8 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
enum nl80211_tx_power_setting type,
int mbm)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv;
struct mwifiex_power_cfg power_cfg;
int dbm = MBM_TO_DBM(mbm);
@ -109,6 +129,8 @@ mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
power_cfg.is_power_auto = 1;
}
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
return mwifiex_set_tx_power(priv, &power_cfg);
}
@ -148,7 +170,7 @@ mwifiex_cfg80211_set_default_key(struct wiphy *wiphy, struct net_device *netdev,
if (!priv->sec_info.wep_enabled)
return 0;
if (mwifiex_set_encode(priv, NULL, 0, key_index, 0)) {
if (mwifiex_set_encode(priv, NULL, 0, key_index, NULL, 0)) {
wiphy_err(wiphy, "set default Tx key index\n");
return -EFAULT;
}
@ -165,9 +187,11 @@ mwifiex_cfg80211_add_key(struct wiphy *wiphy, struct net_device *netdev,
struct key_params *params)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(netdev);
const u8 bc_mac[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
const u8 *peer_mac = pairwise ? mac_addr : bc_mac;
if (mwifiex_set_encode(priv, params->key, params->key_len,
key_index, 0)) {
key_index, peer_mac, 0)) {
wiphy_err(wiphy, "crypto keys added\n");
return -EFAULT;
}
@ -192,13 +216,13 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
enum ieee80211_band band;
struct ieee80211_supported_band *sband;
struct ieee80211_channel *ch;
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv;
struct mwifiex_802_11d_domain_reg *domain_info = &adapter->domain_reg;
/* Set country code */
domain_info->country_code[0] = priv->country_code[0];
domain_info->country_code[1] = priv->country_code[1];
domain_info->country_code[0] = adapter->country_code[0];
domain_info->country_code[1] = adapter->country_code[1];
domain_info->country_code[2] = ' ';
band = mwifiex_band_to_radio_type(adapter->config_bands);
@ -250,6 +274,8 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
domain_info->no_of_triplet = no_of_triplet;
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
if (mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11D_DOMAIN_INFO,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "11D: setting domain info in FW\n");
@ -272,12 +298,12 @@ static int mwifiex_send_domain_info_cmd_fw(struct wiphy *wiphy)
static int mwifiex_reg_notifier(struct wiphy *wiphy,
struct regulatory_request *request)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for domain"
" %c%c\n", request->alpha2[0], request->alpha2[1]);
wiphy_dbg(wiphy, "info: cfg80211 regulatory domain callback for %c%c\n",
request->alpha2[0], request->alpha2[1]);
memcpy(priv->country_code, request->alpha2, sizeof(request->alpha2));
memcpy(adapter->country_code, request->alpha2, sizeof(request->alpha2));
switch (request->initiator) {
case NL80211_REGDOM_SET_BY_DRIVER:
@ -361,33 +387,10 @@ mwifiex_set_rf_channel(struct mwifiex_private *priv,
if (mwifiex_bss_set_channel(priv, &cfp))
return -EFAULT;
return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
}
/*
* CFG802.11 operation handler to set channel.
*
* This function can only be used when station is not connected.
*/
static int
mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan,
enum nl80211_channel_type channel_type)
{
struct mwifiex_private *priv;
if (dev)
priv = mwifiex_netdev_get_priv(dev);
if (priv->bss_type == MWIFIEX_BSS_TYPE_STA)
return mwifiex_drv_change_adhoc_chan(priv, cfp.channel);
else
priv = mwifiex_cfg80211_get_priv(wiphy);
if (priv->media_connected) {
wiphy_err(wiphy, "This setting is valid only when station "
"is not connected\n");
return -EINVAL;
}
return mwifiex_set_rf_channel(priv, chan, channel_type);
return mwifiex_uap_set_channel(priv, cfp.channel);
}
/*
@ -399,18 +402,13 @@ mwifiex_cfg80211_set_channel(struct wiphy *wiphy, struct net_device *dev,
static int
mwifiex_set_frag(struct mwifiex_private *priv, u32 frag_thr)
{
int ret;
if (frag_thr < MWIFIEX_FRAG_MIN_VALUE ||
frag_thr > MWIFIEX_FRAG_MAX_VALUE)
return -EINVAL;
frag_thr = MWIFIEX_FRAG_MAX_VALUE;
/* Send request to firmware */
ret = mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
&frag_thr);
return ret;
return mwifiex_send_cmd_sync(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, FRAG_THRESH_I,
&frag_thr);
}
/*
@ -439,19 +437,85 @@ mwifiex_set_rts(struct mwifiex_private *priv, u32 rts_thr)
static int
mwifiex_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
int ret = 0;
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv;
struct mwifiex_uap_bss_param *bss_cfg;
int ret, bss_started, i;
if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
ret = mwifiex_set_rts(priv, wiphy->rts_threshold);
if (ret)
return ret;
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
switch (priv->bss_role) {
case MWIFIEX_BSS_ROLE_UAP:
bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param),
GFP_KERNEL);
if (!bss_cfg)
return -ENOMEM;
mwifiex_set_sys_config_invalid_data(bss_cfg);
if (changed & WIPHY_PARAM_RTS_THRESHOLD)
bss_cfg->rts_threshold = wiphy->rts_threshold;
if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
bss_cfg->frag_threshold = wiphy->frag_threshold;
if (changed & WIPHY_PARAM_RETRY_LONG)
bss_cfg->retry_limit = wiphy->retry_long;
bss_started = priv->bss_started;
ret = mwifiex_send_cmd_sync(priv,
HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0,
NULL);
if (ret) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
kfree(bss_cfg);
return ret;
}
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_UAP_SYS_CONFIG,
HostCmd_ACT_GEN_SET,
UAP_BSS_PARAMS_I, bss_cfg);
kfree(bss_cfg);
if (ret) {
wiphy_err(wiphy, "Failed to set bss config\n");
return ret;
}
if (!bss_started)
break;
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_UAP_BSS_START,
HostCmd_ACT_GEN_SET, 0,
NULL);
if (ret) {
wiphy_err(wiphy, "Failed to start BSS\n");
return ret;
}
break;
case MWIFIEX_BSS_ROLE_STA:
if (changed & WIPHY_PARAM_RTS_THRESHOLD) {
ret = mwifiex_set_rts(priv,
wiphy->rts_threshold);
if (ret)
return ret;
}
if (changed & WIPHY_PARAM_FRAG_THRESHOLD) {
ret = mwifiex_set_frag(priv,
wiphy->frag_threshold);
if (ret)
return ret;
}
break;
}
}
if (changed & WIPHY_PARAM_FRAG_THRESHOLD)
ret = mwifiex_set_frag(priv, wiphy->frag_threshold);
return ret;
return 0;
}
/*
@ -466,31 +530,59 @@ mwifiex_cfg80211_change_virtual_intf(struct wiphy *wiphy,
int ret;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (priv->bss_mode == type) {
wiphy_warn(wiphy, "already set to required type\n");
return 0;
}
priv->bss_mode = type;
switch (type) {
switch (dev->ieee80211_ptr->iftype) {
case NL80211_IFTYPE_ADHOC:
dev->ieee80211_ptr->iftype = NL80211_IFTYPE_ADHOC;
wiphy_dbg(wiphy, "info: setting interface type to adhoc\n");
switch (type) {
case NL80211_IFTYPE_STATION:
break;
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as IBSS\n", dev->name);
case NL80211_IFTYPE_ADHOC: /* This shouldn't happen */
return 0;
case NL80211_IFTYPE_AP:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
return -EOPNOTSUPP;
}
break;
case NL80211_IFTYPE_STATION:
dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
wiphy_dbg(wiphy, "info: setting interface type to managed\n");
switch (type) {
case NL80211_IFTYPE_ADHOC:
break;
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as STA\n", dev->name);
case NL80211_IFTYPE_STATION: /* This shouldn't happen */
return 0;
case NL80211_IFTYPE_AP:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
return -EOPNOTSUPP;
}
break;
case NL80211_IFTYPE_AP:
switch (type) {
case NL80211_IFTYPE_UNSPECIFIED:
wiphy_warn(wiphy, "%s: kept type as AP\n", dev->name);
case NL80211_IFTYPE_AP: /* This shouldn't happen */
return 0;
case NL80211_IFTYPE_ADHOC:
case NL80211_IFTYPE_STATION:
default:
wiphy_err(wiphy, "%s: changing to %d not supported\n",
dev->name, type);
return -EOPNOTSUPP;
}
break;
case NL80211_IFTYPE_UNSPECIFIED:
dev->ieee80211_ptr->iftype = NL80211_IFTYPE_STATION;
wiphy_dbg(wiphy, "info: setting interface type to auto\n");
return 0;
default:
wiphy_err(wiphy, "unknown interface type: %d\n", type);
return -EINVAL;
wiphy_err(wiphy, "%s: unknown iftype: %d\n",
dev->name, dev->ieee80211_ptr->iftype);
return -EOPNOTSUPP;
}
dev->ieee80211_ptr->iftype = type;
priv->bss_mode = type;
mwifiex_deauthenticate(priv, NULL);
priv->sec_info.authentication_mode = NL80211_AUTHTYPE_OPEN_SYSTEM;
@ -804,6 +896,90 @@ static int mwifiex_cfg80211_set_cqm_rssi_config(struct wiphy *wiphy,
return 0;
}
/* cfg80211 operation handler for stop ap.
* Function stops BSS running at uAP interface.
*/
static int mwifiex_cfg80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
{
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (mwifiex_del_mgmt_ies(priv))
wiphy_err(wiphy, "Failed to delete mgmt IEs!\n");
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
return -1;
}
return 0;
}
/* cfg80211 operation handler for start_ap.
* Function sets beacon period, DTIM period, SSID and security into
* AP config structure.
* AP is configured with these settings and BSS is started.
*/
static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
struct net_device *dev,
struct cfg80211_ap_settings *params)
{
struct mwifiex_uap_bss_param *bss_cfg;
struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP)
return -1;
if (mwifiex_set_mgmt_ies(priv, params))
return -1;
bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
if (!bss_cfg)
return -ENOMEM;
mwifiex_set_sys_config_invalid_data(bss_cfg);
if (params->beacon_interval)
bss_cfg->beacon_period = params->beacon_interval;
if (params->dtim_period)
bss_cfg->dtim_period = params->dtim_period;
if (params->ssid && params->ssid_len) {
memcpy(bss_cfg->ssid.ssid, params->ssid, params->ssid_len);
bss_cfg->ssid.ssid_len = params->ssid_len;
}
if (mwifiex_set_secure_params(priv, bss_cfg, params)) {
kfree(bss_cfg);
wiphy_err(wiphy, "Failed to parse secuirty parameters!\n");
return -1;
}
if (mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "Failed to stop the BSS\n");
kfree(bss_cfg);
return -1;
}
if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
HostCmd_ACT_GEN_SET,
UAP_BSS_PARAMS_I, bss_cfg)) {
wiphy_err(wiphy, "Failed to set the SSID\n");
kfree(bss_cfg);
return -1;
}
kfree(bss_cfg);
if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_BSS_START,
HostCmd_ACT_GEN_SET, 0, NULL)) {
wiphy_err(wiphy, "Failed to start the BSS\n");
return -1;
}
return 0;
}
/*
* CFG802.11 operation handler for disconnection request.
*
@ -923,7 +1099,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
priv->wep_key_curr_index = 0;
priv->sec_info.encryption_mode = 0;
priv->sec_info.is_authtype_auto = 0;
ret = mwifiex_set_encode(priv, NULL, 0, 0, 1);
ret = mwifiex_set_encode(priv, NULL, 0, 0, NULL, 1);
if (mode == NL80211_IFTYPE_ADHOC) {
/* "privacy" is set only for ad-hoc mode */
@ -971,7 +1147,7 @@ mwifiex_cfg80211_assoc(struct mwifiex_private *priv, size_t ssid_len, u8 *ssid,
" with key len %d\n", sme->key_len);
priv->wep_key_curr_index = sme->key_idx;
ret = mwifiex_set_encode(priv, sme->key, sme->key_len,
sme->key_idx, 0);
sme->key_idx, NULL, 0);
}
}
done:
@ -1050,6 +1226,11 @@ mwifiex_cfg80211_connect(struct wiphy *wiphy, struct net_device *dev,
goto done;
}
if (priv->bss_mode == NL80211_IFTYPE_AP) {
wiphy_err(wiphy, "skip association request for AP interface\n");
goto done;
}
wiphy_dbg(wiphy, "info: Trying to associate to %s and bssid %pM\n",
(char *) sme->ssid, sme->bssid);
@ -1283,15 +1464,12 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
u32 *flags,
struct vif_params *params)
{
struct mwifiex_private *priv = mwifiex_cfg80211_get_priv(wiphy);
struct mwifiex_adapter *adapter;
struct mwifiex_adapter *adapter = mwifiex_cfg80211_get_adapter(wiphy);
struct mwifiex_private *priv;
struct net_device *dev;
void *mdev_priv;
struct wireless_dev *wdev;
if (!priv)
return NULL;
adapter = priv->adapter;
if (!adapter)
return NULL;
@ -1299,12 +1477,21 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
case NL80211_IFTYPE_UNSPECIFIED:
case NL80211_IFTYPE_STATION:
case NL80211_IFTYPE_ADHOC:
priv = adapter->priv[MWIFIEX_BSS_TYPE_STA];
if (priv->bss_mode) {
wiphy_err(wiphy, "cannot create multiple"
" station/adhoc interfaces\n");
wiphy_err(wiphy,
"cannot create multiple sta/adhoc ifaces\n");
return NULL;
}
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!wdev)
return NULL;
wdev->wiphy = wiphy;
priv->wdev = wdev;
wdev->iftype = NL80211_IFTYPE_STATION;
if (type == NL80211_IFTYPE_UNSPECIFIED)
priv->bss_mode = NL80211_IFTYPE_STATION;
else
@ -1312,10 +1499,35 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
priv->bss_type = MWIFIEX_BSS_TYPE_STA;
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
priv->bss_priority = 0;
priv->bss_priority = MWIFIEX_BSS_ROLE_STA;
priv->bss_role = MWIFIEX_BSS_ROLE_STA;
priv->bss_num = 0;
break;
case NL80211_IFTYPE_AP:
priv = adapter->priv[MWIFIEX_BSS_TYPE_UAP];
if (priv->bss_mode) {
wiphy_err(wiphy, "Can't create multiple AP interfaces");
return NULL;
}
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!wdev)
return NULL;
priv->wdev = wdev;
wdev->wiphy = wiphy;
wdev->iftype = NL80211_IFTYPE_AP;
priv->bss_type = MWIFIEX_BSS_TYPE_UAP;
priv->frame_type = MWIFIEX_DATA_FRAME_TYPE_ETH_II;
priv->bss_priority = MWIFIEX_BSS_ROLE_UAP;
priv->bss_role = MWIFIEX_BSS_ROLE_UAP;
priv->bss_started = 0;
priv->bss_num = 0;
priv->bss_mode = type;
break;
default:
wiphy_err(wiphy, "type not supported\n");
@ -1329,6 +1541,15 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
goto error;
}
mwifiex_init_priv_params(priv, dev);
priv->netdev = dev;
mwifiex_setup_ht_caps(&wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap, priv);
if (adapter->config_bands & BAND_A)
mwifiex_setup_ht_caps(
&wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap, priv);
dev_net_set(dev, wiphy_net(wiphy));
dev->ieee80211_ptr = priv->wdev;
dev->ieee80211_ptr->iftype = priv->bss_mode;
@ -1343,9 +1564,6 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
mdev_priv = netdev_priv(dev);
*((unsigned long *) mdev_priv) = (unsigned long) priv;
priv->netdev = dev;
mwifiex_init_priv_params(priv, dev);
SET_NETDEV_DEV(dev, adapter->dev);
/* Register network device */
@ -1417,7 +1635,6 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.get_station = mwifiex_cfg80211_get_station,
.dump_station = mwifiex_cfg80211_dump_station,
.set_wiphy_params = mwifiex_cfg80211_set_wiphy_params,
.set_channel = mwifiex_cfg80211_set_channel,
.join_ibss = mwifiex_cfg80211_join_ibss,
.leave_ibss = mwifiex_cfg80211_leave_ibss,
.add_key = mwifiex_cfg80211_add_key,
@ -1426,6 +1643,8 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
.set_power_mgmt = mwifiex_cfg80211_set_power_mgmt,
.set_tx_power = mwifiex_cfg80211_set_tx_power,
.set_bitrate_mask = mwifiex_cfg80211_set_bitrate_mask,
.start_ap = mwifiex_cfg80211_start_ap,
.stop_ap = mwifiex_cfg80211_stop_ap,
.set_cqm_rssi_config = mwifiex_cfg80211_set_cqm_rssi_config,
};
@ -1436,82 +1655,67 @@ static struct cfg80211_ops mwifiex_cfg80211_ops = {
* default parameters and handler function pointers, and finally
* registers the device.
*/
int mwifiex_register_cfg80211(struct mwifiex_private *priv)
int mwifiex_register_cfg80211(struct mwifiex_adapter *adapter)
{
int ret;
void *wdev_priv;
struct wireless_dev *wdev;
struct ieee80211_sta_ht_cap *ht_info;
struct wiphy *wiphy;
struct mwifiex_private *priv = adapter->priv[MWIFIEX_BSS_TYPE_STA];
u8 *country_code;
wdev = kzalloc(sizeof(struct wireless_dev), GFP_KERNEL);
if (!wdev) {
dev_err(priv->adapter->dev, "%s: allocating wireless device\n",
__func__);
/* create a new wiphy for use with cfg80211 */
wiphy = wiphy_new(&mwifiex_cfg80211_ops,
sizeof(struct mwifiex_adapter *));
if (!wiphy) {
dev_err(adapter->dev, "%s: creating new wiphy\n", __func__);
return -ENOMEM;
}
wdev->wiphy =
wiphy_new(&mwifiex_cfg80211_ops,
sizeof(struct mwifiex_private *));
if (!wdev->wiphy) {
kfree(wdev);
return -ENOMEM;
}
wdev->iftype = NL80211_IFTYPE_STATION;
wdev->wiphy->max_scan_ssids = 10;
wdev->wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
wdev->wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC);
wiphy->max_scan_ssids = MWIFIEX_MAX_SSID_LIST_LENGTH;
wiphy->max_scan_ie_len = MWIFIEX_MAX_VSIE_LEN;
wiphy->interface_modes = BIT(NL80211_IFTYPE_STATION) |
BIT(NL80211_IFTYPE_ADHOC) |
BIT(NL80211_IFTYPE_AP);
wdev->wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
ht_info = &wdev->wiphy->bands[IEEE80211_BAND_2GHZ]->ht_cap;
mwifiex_setup_ht_caps(ht_info, priv);
wiphy->bands[IEEE80211_BAND_2GHZ] = &mwifiex_band_2ghz;
if (adapter->config_bands & BAND_A)
wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
else
wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
if (priv->adapter->config_bands & BAND_A) {
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = &mwifiex_band_5ghz;
ht_info = &wdev->wiphy->bands[IEEE80211_BAND_5GHZ]->ht_cap;
mwifiex_setup_ht_caps(ht_info, priv);
} else {
wdev->wiphy->bands[IEEE80211_BAND_5GHZ] = NULL;
}
wiphy->iface_combinations = &mwifiex_iface_comb_ap_sta;
wiphy->n_iface_combinations = 1;
/* Initialize cipher suits */
wdev->wiphy->cipher_suites = mwifiex_cipher_suites;
wdev->wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
wiphy->cipher_suites = mwifiex_cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(mwifiex_cipher_suites);
memcpy(wdev->wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
wdev->wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
memcpy(wiphy->perm_addr, priv->curr_addr, ETH_ALEN);
wiphy->signal_type = CFG80211_SIGNAL_TYPE_MBM;
wiphy->flags |= WIPHY_FLAG_HAVE_AP_SME | WIPHY_FLAG_CUSTOM_REGULATORY;
/* Reserve space for mwifiex specific private data for BSS */
wdev->wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
wiphy->bss_priv_size = sizeof(struct mwifiex_bss_priv);
wdev->wiphy->reg_notifier = mwifiex_reg_notifier;
wiphy->reg_notifier = mwifiex_reg_notifier;
/* Set struct mwifiex_private pointer in wiphy_priv */
wdev_priv = wiphy_priv(wdev->wiphy);
/* Set struct mwifiex_adapter pointer in wiphy_priv */
wdev_priv = wiphy_priv(wiphy);
*(unsigned long *)wdev_priv = (unsigned long)adapter;
*(unsigned long *) wdev_priv = (unsigned long) priv;
set_wiphy_dev(wiphy, (struct device *)priv->adapter->dev);
set_wiphy_dev(wdev->wiphy, (struct device *) priv->adapter->dev);
ret = wiphy_register(wdev->wiphy);
ret = wiphy_register(wiphy);
if (ret < 0) {
dev_err(priv->adapter->dev, "%s: registering cfg80211 device\n",
__func__);
wiphy_free(wdev->wiphy);
kfree(wdev);
dev_err(adapter->dev,
"%s: wiphy_register failed: %d\n", __func__, ret);
wiphy_free(wiphy);
return ret;
} else {
dev_dbg(priv->adapter->dev,
"info: successfully registered wiphy device\n");
}
country_code = mwifiex_11d_code_2_region(priv->adapter->region_code);
if (country_code && regulatory_hint(wdev->wiphy, country_code))
dev_err(priv->adapter->dev,
"%s: regulatory_hint failed\n", __func__);
priv->wdev = wdev;
if (country_code && regulatory_hint(wiphy, country_code))
dev_err(adapter->dev, "regulatory_hint() failed\n");
adapter->wiphy = wiphy;
return ret;
}

View File

@ -24,6 +24,6 @@
#include "main.h"
int mwifiex_register_cfg80211(struct mwifiex_private *);
int mwifiex_register_cfg80211(struct mwifiex_adapter *);
#endif

View File

@ -440,6 +440,11 @@ int mwifiex_process_event(struct mwifiex_adapter *adapter)
do_gettimeofday(&tstamp);
dev_dbg(adapter->dev, "event: %lu.%lu: cause: %#x\n",
tstamp.tv_sec, tstamp.tv_usec, eventcause);
} else {
/* Handle PS_SLEEP/AWAKE events on STA */
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
if (!priv)
priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_ANY);
}
ret = mwifiex_process_sta_event(priv);
@ -540,8 +545,20 @@ int mwifiex_send_cmd_async(struct mwifiex_private *priv, uint16_t cmd_no,
/* Prepare command */
if (cmd_no) {
ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action,
cmd_oid, data_buf, cmd_ptr);
switch (cmd_no) {
case HostCmd_CMD_UAP_SYS_CONFIG:
case HostCmd_CMD_UAP_BSS_START:
case HostCmd_CMD_UAP_BSS_STOP:
ret = mwifiex_uap_prepare_cmd(priv, cmd_no, cmd_action,
cmd_oid, data_buf,
cmd_ptr);
break;
default:
ret = mwifiex_sta_prepare_cmd(priv, cmd_no, cmd_action,
cmd_oid, data_buf,
cmd_ptr);
break;
}
} else {
ret = mwifiex_cmd_host_cmd(priv, cmd_ptr, data_buf);
cmd_node->cmd_flag |= CMD_F_HOSTCMD;

View File

@ -28,7 +28,7 @@
#include <linux/ieee80211.h>
#define MWIFIEX_MAX_BSS_NUM (1)
#define MWIFIEX_MAX_BSS_NUM (2)
#define MWIFIEX_MIN_DATA_HEADER_LEN 36 /* sizeof(mwifiex_txpd)
* + 4 byte alignment
@ -55,11 +55,17 @@
#define MWIFIEX_RX_DATA_BUF_SIZE (4 * 1024)
#define MWIFIEX_RX_CMD_BUF_SIZE (2 * 1024)
#define MAX_BEACON_PERIOD (4000)
#define MIN_BEACON_PERIOD (50)
#define MAX_DTIM_PERIOD (100)
#define MIN_DTIM_PERIOD (1)
#define MWIFIEX_RTS_MIN_VALUE (0)
#define MWIFIEX_RTS_MAX_VALUE (2347)
#define MWIFIEX_FRAG_MIN_VALUE (256)
#define MWIFIEX_FRAG_MAX_VALUE (2346)
#define MWIFIEX_RETRY_LIMIT 14
#define MWIFIEX_SDIO_BLOCK_SIZE 256
#define MWIFIEX_BUF_FLAG_REQUEUED_PKT BIT(0)
@ -92,6 +98,11 @@ struct mwifiex_fw_image {
u32 fw_len;
};
struct mwifiex_802_11_ssid {
u32 ssid_len;
u8 ssid[IEEE80211_MAX_SSID_LEN];
};
struct mwifiex_wait_queue {
wait_queue_head_t wait;
int status;

View File

@ -93,6 +93,20 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define CAL_SNR(RSSI, NF) ((s16)((s16)(RSSI)-(s16)(NF)))
#define UAP_BSS_PARAMS_I 0
#define UAP_CUSTOM_IE_I 1
#define MWIFIEX_AUTO_IDX_MASK 0xffff
#define MWIFIEX_DELETE_MASK 0x0000
#define MGMT_MASK_ASSOC_REQ 0x01
#define MGMT_MASK_REASSOC_REQ 0x04
#define MGMT_MASK_ASSOC_RESP 0x02
#define MGMT_MASK_REASSOC_RESP 0x08
#define MGMT_MASK_PROBE_REQ 0x10
#define MGMT_MASK_PROBE_RESP 0x20
#define MGMT_MASK_BEACON 0x100
#define TLV_TYPE_UAP_SSID 0x0000
#define PROPRIETARY_TLV_BASE_ID 0x0100
#define TLV_TYPE_KEY_MATERIAL (PROPRIETARY_TLV_BASE_ID + 0)
#define TLV_TYPE_CHANLIST (PROPRIETARY_TLV_BASE_ID + 1)
@ -104,14 +118,26 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define TLV_TYPE_TSFTIMESTAMP (PROPRIETARY_TLV_BASE_ID + 19)
#define TLV_TYPE_RSSI_HIGH (PROPRIETARY_TLV_BASE_ID + 22)
#define TLV_TYPE_AUTH_TYPE (PROPRIETARY_TLV_BASE_ID + 31)
#define TLV_TYPE_STA_MAC_ADDR (PROPRIETARY_TLV_BASE_ID + 32)
#define TLV_TYPE_CHANNELBANDLIST (PROPRIETARY_TLV_BASE_ID + 42)
#define TLV_TYPE_UAP_BEACON_PERIOD (PROPRIETARY_TLV_BASE_ID + 44)
#define TLV_TYPE_UAP_DTIM_PERIOD (PROPRIETARY_TLV_BASE_ID + 45)
#define TLV_TYPE_UAP_RTS_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 51)
#define TLV_TYPE_UAP_WPA_PASSPHRASE (PROPRIETARY_TLV_BASE_ID + 60)
#define TLV_TYPE_UAP_ENCRY_PROTOCOL (PROPRIETARY_TLV_BASE_ID + 64)
#define TLV_TYPE_UAP_AKMP (PROPRIETARY_TLV_BASE_ID + 65)
#define TLV_TYPE_UAP_FRAG_THRESHOLD (PROPRIETARY_TLV_BASE_ID + 70)
#define TLV_TYPE_RATE_DROP_CONTROL (PROPRIETARY_TLV_BASE_ID + 82)
#define TLV_TYPE_RATE_SCOPE (PROPRIETARY_TLV_BASE_ID + 83)
#define TLV_TYPE_POWER_GROUP (PROPRIETARY_TLV_BASE_ID + 84)
#define TLV_TYPE_UAP_RETRY_LIMIT (PROPRIETARY_TLV_BASE_ID + 93)
#define TLV_TYPE_WAPI_IE (PROPRIETARY_TLV_BASE_ID + 94)
#define TLV_TYPE_UAP_MGMT_FRAME (PROPRIETARY_TLV_BASE_ID + 104)
#define TLV_TYPE_MGMT_IE (PROPRIETARY_TLV_BASE_ID + 105)
#define TLV_TYPE_AUTO_DS_PARAM (PROPRIETARY_TLV_BASE_ID + 113)
#define TLV_TYPE_PS_PARAM (PROPRIETARY_TLV_BASE_ID + 114)
#define TLV_TYPE_PWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 145)
#define TLV_TYPE_GWK_CIPHER (PROPRIETARY_TLV_BASE_ID + 146)
#define MWIFIEX_TX_DATA_BUF_SIZE_2K 2048
@ -209,6 +235,9 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_RSSI_INFO 0x00a4
#define HostCmd_CMD_FUNC_INIT 0x00a9
#define HostCmd_CMD_FUNC_SHUTDOWN 0x00aa
#define HostCmd_CMD_UAP_SYS_CONFIG 0x00b0
#define HostCmd_CMD_UAP_BSS_START 0x00b1
#define HostCmd_CMD_UAP_BSS_STOP 0x00b2
#define HostCmd_CMD_11N_CFG 0x00cd
#define HostCmd_CMD_11N_ADDBA_REQ 0x00ce
#define HostCmd_CMD_11N_ADDBA_RSP 0x00cf
@ -223,6 +252,19 @@ enum MWIFIEX_802_11_PRIVACY_FILTER {
#define HostCmd_CMD_SET_BSS_MODE 0x00f7
#define HostCmd_CMD_PCIE_DESC_DETAILS 0x00fa
#define PROTOCOL_NO_SECURITY 0x01
#define PROTOCOL_STATIC_WEP 0x02
#define PROTOCOL_WPA 0x08
#define PROTOCOL_WPA2 0x20
#define PROTOCOL_WPA2_MIXED 0x28
#define PROTOCOL_EAP 0x40
#define KEY_MGMT_NONE 0x04
#define KEY_MGMT_PSK 0x02
#define KEY_MGMT_EAP 0x01
#define CIPHER_TKIP 0x04
#define CIPHER_AES_CCMP 0x08
#define VALID_CIPHER_BITMAP 0x0c
enum ENH_PS_MODES {
EN_PS = 1,
DIS_PS = 2,
@ -313,15 +355,20 @@ enum ENH_PS_MODES {
#define EVENT_DATA_SNR_HIGH 0x00000027
#define EVENT_LINK_QUALITY 0x00000028
#define EVENT_PORT_RELEASE 0x0000002b
#define EVENT_UAP_STA_DEAUTH 0x0000002c
#define EVENT_UAP_STA_ASSOC 0x0000002d
#define EVENT_UAP_BSS_START 0x0000002e
#define EVENT_PRE_BEACON_LOST 0x00000031
#define EVENT_ADDBA 0x00000033
#define EVENT_DELBA 0x00000034
#define EVENT_BA_STREAM_TIEMOUT 0x00000037
#define EVENT_AMSDU_AGGR_CTRL 0x00000042
#define EVENT_UAP_BSS_IDLE 0x00000043
#define EVENT_UAP_BSS_ACTIVE 0x00000044
#define EVENT_WEP_ICV_ERR 0x00000046
#define EVENT_HS_ACT_REQ 0x00000047
#define EVENT_BW_CHANGE 0x00000048
#define EVENT_UAP_MIC_COUNTERMEASURES 0x0000004c
#define EVENT_HOSTWAKE_STAIE 0x0000004d
#define EVENT_ID_MASK 0xffff
@ -1103,6 +1150,101 @@ struct host_cmd_ds_802_11_eeprom_access {
u8 value;
} __packed;
struct host_cmd_tlv {
__le16 type;
__le16 len;
} __packed;
struct mwifiex_assoc_event {
u8 sta_addr[ETH_ALEN];
__le16 type;
__le16 len;
__le16 frame_control;
__le16 cap_info;
__le16 listen_interval;
u8 data[0];
} __packed;
struct host_cmd_ds_sys_config {
__le16 action;
u8 tlv[0];
};
struct host_cmd_tlv_akmp {
struct host_cmd_tlv tlv;
__le16 key_mgmt;
__le16 key_mgmt_operation;
} __packed;
struct host_cmd_tlv_pwk_cipher {
struct host_cmd_tlv tlv;
__le16 proto;
u8 cipher;
u8 reserved;
} __packed;
struct host_cmd_tlv_gwk_cipher {
struct host_cmd_tlv tlv;
u8 cipher;
u8 reserved;
} __packed;
struct host_cmd_tlv_passphrase {
struct host_cmd_tlv tlv;
u8 passphrase[0];
} __packed;
struct host_cmd_tlv_auth_type {
struct host_cmd_tlv tlv;
u8 auth_type;
} __packed;
struct host_cmd_tlv_encrypt_protocol {
struct host_cmd_tlv tlv;
__le16 proto;
} __packed;
struct host_cmd_tlv_ssid {
struct host_cmd_tlv tlv;
u8 ssid[0];
} __packed;
struct host_cmd_tlv_beacon_period {
struct host_cmd_tlv tlv;
__le16 period;
} __packed;
struct host_cmd_tlv_dtim_period {
struct host_cmd_tlv tlv;
u8 period;
} __packed;
struct host_cmd_tlv_frag_threshold {
struct host_cmd_tlv tlv;
__le16 frag_thr;
} __packed;
struct host_cmd_tlv_rts_threshold {
struct host_cmd_tlv tlv;
__le16 rts_thr;
} __packed;
struct host_cmd_tlv_retry_limit {
struct host_cmd_tlv tlv;
u8 limit;
} __packed;
struct host_cmd_tlv_mac_addr {
struct host_cmd_tlv tlv;
u8 mac_addr[ETH_ALEN];
} __packed;
struct host_cmd_tlv_channel_band {
struct host_cmd_tlv tlv;
u8 band_config;
u8 channel;
} __packed;
struct host_cmd_ds_802_11_rf_channel {
__le16 action;
__le16 current_channel;
@ -1167,6 +1309,20 @@ struct host_cmd_ds_802_11_subsc_evt {
__le16 events;
} __packed;
struct mwifiex_ie {
__le16 ie_index;
__le16 mgmt_subtype_mask;
__le16 ie_length;
u8 ie_buffer[IEEE_MAX_IE_SIZE];
} __packed;
#define MAX_MGMT_IE_INDEX 16
struct mwifiex_ie_list {
__le16 type;
__le16 len;
struct mwifiex_ie ie_list[MAX_MGMT_IE_INDEX];
} __packed;
struct host_cmd_ds_command {
__le16 command;
__le16 size;
@ -1217,6 +1373,7 @@ struct host_cmd_ds_command {
struct host_cmd_ds_pcie_details pcie_host_spec;
struct host_cmd_ds_802_11_eeprom_access eeprom;
struct host_cmd_ds_802_11_subsc_evt subsc_evt;
struct host_cmd_ds_sys_config uap_sys_config;
} params;
} __packed;

View File

@ -0,0 +1,396 @@
/*
* Marvell Wireless LAN device driver: management IE handling- setting and
* deleting IE.
*
* Copyright (C) 2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#include "main.h"
/* This function checks if current IE index is used by any on other interface.
* Return: -1: yes, current IE index is used by someone else.
* 0: no, current IE index is NOT used by other interface.
*/
static int
mwifiex_ie_index_used_by_other_intf(struct mwifiex_private *priv, u16 idx)
{
int i;
struct mwifiex_adapter *adapter = priv->adapter;
struct mwifiex_ie *ie;
for (i = 0; i < adapter->priv_num; i++) {
if (adapter->priv[i] != priv) {
ie = &adapter->priv[i]->mgmt_ie[idx];
if (ie->mgmt_subtype_mask && ie->ie_length)
return -1;
}
}
return 0;
}
/* Get unused IE index. This index will be used for setting new IE */
static int
mwifiex_ie_get_autoidx(struct mwifiex_private *priv, u16 subtype_mask,
struct mwifiex_ie *ie, u16 *index)
{
u16 mask, len, i;
for (i = 0; i < priv->adapter->max_mgmt_ie_index; i++) {
mask = le16_to_cpu(priv->mgmt_ie[i].mgmt_subtype_mask);
len = le16_to_cpu(priv->mgmt_ie[i].ie_length) +
le16_to_cpu(ie->ie_length);
if (mask == MWIFIEX_AUTO_IDX_MASK)
continue;
if (mask == subtype_mask) {
if (len > IEEE_MAX_IE_SIZE)
continue;
*index = i;
return 0;
}
if (!priv->mgmt_ie[i].ie_length) {
if (mwifiex_ie_index_used_by_other_intf(priv, i))
continue;
*index = i;
return 0;
}
}
return -1;
}
/* This function prepares IE data buffer for command to be sent to FW */
static int
mwifiex_update_autoindex_ies(struct mwifiex_private *priv,
struct mwifiex_ie_list *ie_list)
{
u16 travel_len, index, mask;
s16 input_len;
struct mwifiex_ie *ie;
u8 *tmp;
input_len = le16_to_cpu(ie_list->len);
travel_len = sizeof(struct host_cmd_tlv);
ie_list->len = 0;
while (input_len > 0) {
ie = (struct mwifiex_ie *)(((u8 *)ie_list) + travel_len);
input_len -= le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE;
travel_len += le16_to_cpu(ie->ie_length) + MWIFIEX_IE_HDR_SIZE;
index = le16_to_cpu(ie->ie_index);
mask = le16_to_cpu(ie->mgmt_subtype_mask);
if (index == MWIFIEX_AUTO_IDX_MASK) {
/* automatic addition */
if (mwifiex_ie_get_autoidx(priv, mask, ie, &index))
return -1;
if (index == MWIFIEX_AUTO_IDX_MASK)
return -1;
tmp = (u8 *)&priv->mgmt_ie[index].ie_buffer;
tmp += le16_to_cpu(priv->mgmt_ie[index].ie_length);
memcpy(tmp, &ie->ie_buffer, le16_to_cpu(ie->ie_length));
le16_add_cpu(&priv->mgmt_ie[index].ie_length,
le16_to_cpu(ie->ie_length));
priv->mgmt_ie[index].ie_index = cpu_to_le16(index);
priv->mgmt_ie[index].mgmt_subtype_mask =
cpu_to_le16(mask);
ie->ie_index = cpu_to_le16(index);
ie->ie_length = priv->mgmt_ie[index].ie_length;
memcpy(&ie->ie_buffer, &priv->mgmt_ie[index].ie_buffer,
le16_to_cpu(priv->mgmt_ie[index].ie_length));
} else {
if (mask != MWIFIEX_DELETE_MASK)
return -1;
/*
* Check if this index is being used on any
* other interface.
*/
if (mwifiex_ie_index_used_by_other_intf(priv, index))
return -1;
ie->ie_length = 0;
memcpy(&priv->mgmt_ie[index], ie,
sizeof(struct mwifiex_ie));
}
le16_add_cpu(&ie_list->len,
le16_to_cpu(priv->mgmt_ie[index].ie_length) +
MWIFIEX_IE_HDR_SIZE);
}
if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_UAP)
return mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
HostCmd_ACT_GEN_SET,
UAP_CUSTOM_IE_I, ie_list);
return 0;
}
/* Copy individual custom IEs for beacon, probe response and assoc response
* and prepare single structure for IE setting.
* This function also updates allocated IE indices from driver.
*/
static int
mwifiex_update_uap_custom_ie(struct mwifiex_private *priv,
struct mwifiex_ie *beacon_ie, u16 *beacon_idx,
struct mwifiex_ie *pr_ie, u16 *probe_idx,
struct mwifiex_ie *ar_ie, u16 *assoc_idx)
{
struct mwifiex_ie_list *ap_custom_ie;
u8 *pos;
u16 len;
int ret;
ap_custom_ie = kzalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!ap_custom_ie)
return -ENOMEM;
ap_custom_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
pos = (u8 *)ap_custom_ie->ie_list;
if (beacon_ie) {
len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
le16_to_cpu(beacon_ie->ie_length);
memcpy(pos, beacon_ie, len);
pos += len;
le16_add_cpu(&ap_custom_ie->len, len);
}
if (pr_ie) {
len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
le16_to_cpu(pr_ie->ie_length);
memcpy(pos, pr_ie, len);
pos += len;
le16_add_cpu(&ap_custom_ie->len, len);
}
if (ar_ie) {
len = sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE +
le16_to_cpu(ar_ie->ie_length);
memcpy(pos, ar_ie, len);
pos += len;
le16_add_cpu(&ap_custom_ie->len, len);
}
ret = mwifiex_update_autoindex_ies(priv, ap_custom_ie);
pos = (u8 *)(&ap_custom_ie->ie_list[0].ie_index);
if (beacon_ie && *beacon_idx == MWIFIEX_AUTO_IDX_MASK) {
/* save beacon ie index after auto-indexing */
*beacon_idx = le16_to_cpu(ap_custom_ie->ie_list[0].ie_index);
len = sizeof(*beacon_ie) - IEEE_MAX_IE_SIZE +
le16_to_cpu(beacon_ie->ie_length);
pos += len;
}
if (pr_ie && le16_to_cpu(pr_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK) {
/* save probe resp ie index after auto-indexing */
*probe_idx = *((u16 *)pos);
len = sizeof(*pr_ie) - IEEE_MAX_IE_SIZE +
le16_to_cpu(pr_ie->ie_length);
pos += len;
}
if (ar_ie && le16_to_cpu(ar_ie->ie_index) == MWIFIEX_AUTO_IDX_MASK)
/* save assoc resp ie index after auto-indexing */
*assoc_idx = *((u16 *)pos);
return ret;
}
/* This function parses different IEs- Tail IEs, beacon IEs, probe response IEs,
* association response IEs from cfg80211_ap_settings function and sets these IE
* to FW.
*/
int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
struct cfg80211_ap_settings *params)
{
struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
struct ieee_types_header *ie = NULL;
u16 beacon_idx = MWIFIEX_AUTO_IDX_MASK, pr_idx = MWIFIEX_AUTO_IDX_MASK;
u16 ar_idx = MWIFIEX_AUTO_IDX_MASK, rsn_idx = MWIFIEX_AUTO_IDX_MASK;
u16 mask;
int ret = 0;
if (params->beacon.tail && params->beacon.tail_len) {
ie = (void *)cfg80211_find_ie(WLAN_EID_RSN, params->beacon.tail,
params->beacon.tail_len);
if (ie) {
rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!rsn_ie)
return -ENOMEM;
rsn_ie->ie_index = cpu_to_le16(rsn_idx);
mask = MGMT_MASK_BEACON | MGMT_MASK_PROBE_RESP |
MGMT_MASK_ASSOC_RESP;
rsn_ie->mgmt_subtype_mask = cpu_to_le16(mask);
rsn_ie->ie_length = cpu_to_le16(ie->len + 2);
memcpy(rsn_ie->ie_buffer, ie, ie->len + 2);
if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &rsn_idx,
NULL, NULL,
NULL, NULL)) {
ret = -1;
goto done;
}
priv->rsn_idx = rsn_idx;
}
}
if (params->beacon.beacon_ies && params->beacon.beacon_ies_len) {
beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!beacon_ie) {
ret = -ENOMEM;
goto done;
}
beacon_ie->ie_index = cpu_to_le16(beacon_idx);
beacon_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_BEACON);
beacon_ie->ie_length =
cpu_to_le16(params->beacon.beacon_ies_len);
memcpy(beacon_ie->ie_buffer, params->beacon.beacon_ies,
params->beacon.beacon_ies_len);
}
if (params->beacon.proberesp_ies && params->beacon.proberesp_ies_len) {
pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!pr_ie) {
ret = -ENOMEM;
goto done;
}
pr_ie->ie_index = cpu_to_le16(pr_idx);
pr_ie->mgmt_subtype_mask = cpu_to_le16(MGMT_MASK_PROBE_RESP);
pr_ie->ie_length =
cpu_to_le16(params->beacon.proberesp_ies_len);
memcpy(pr_ie->ie_buffer, params->beacon.proberesp_ies,
params->beacon.proberesp_ies_len);
}
if (params->beacon.assocresp_ies && params->beacon.assocresp_ies_len) {
ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!ar_ie) {
ret = -ENOMEM;
goto done;
}
ar_ie->ie_index = cpu_to_le16(ar_idx);
mask = MGMT_MASK_ASSOC_RESP | MGMT_MASK_REASSOC_RESP;
ar_ie->mgmt_subtype_mask = cpu_to_le16(mask);
ar_ie->ie_length =
cpu_to_le16(params->beacon.assocresp_ies_len);
memcpy(ar_ie->ie_buffer, params->beacon.assocresp_ies,
params->beacon.assocresp_ies_len);
}
if (beacon_ie || pr_ie || ar_ie) {
ret = mwifiex_update_uap_custom_ie(priv, beacon_ie,
&beacon_idx, pr_ie,
&pr_idx, ar_ie, &ar_idx);
if (ret)
goto done;
}
priv->beacon_idx = beacon_idx;
priv->proberesp_idx = pr_idx;
priv->assocresp_idx = ar_idx;
done:
kfree(beacon_ie);
kfree(pr_ie);
kfree(ar_ie);
kfree(rsn_ie);
return ret;
}
/* This function removes management IE set */
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv)
{
struct mwifiex_ie *beacon_ie = NULL, *pr_ie = NULL;
struct mwifiex_ie *ar_ie = NULL, *rsn_ie = NULL;
int ret = 0;
if (priv->rsn_idx != MWIFIEX_AUTO_IDX_MASK) {
rsn_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!rsn_ie)
return -ENOMEM;
rsn_ie->ie_index = cpu_to_le16(priv->rsn_idx);
rsn_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
rsn_ie->ie_length = 0;
if (mwifiex_update_uap_custom_ie(priv, rsn_ie, &priv->rsn_idx,
NULL, &priv->proberesp_idx,
NULL, &priv->assocresp_idx)) {
ret = -1;
goto done;
}
priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
}
if (priv->beacon_idx != MWIFIEX_AUTO_IDX_MASK) {
beacon_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!beacon_ie) {
ret = -ENOMEM;
goto done;
}
beacon_ie->ie_index = cpu_to_le16(priv->beacon_idx);
beacon_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
beacon_ie->ie_length = 0;
}
if (priv->proberesp_idx != MWIFIEX_AUTO_IDX_MASK) {
pr_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!pr_ie) {
ret = -ENOMEM;
goto done;
}
pr_ie->ie_index = cpu_to_le16(priv->proberesp_idx);
pr_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
pr_ie->ie_length = 0;
}
if (priv->assocresp_idx != MWIFIEX_AUTO_IDX_MASK) {
ar_ie = kmalloc(sizeof(struct mwifiex_ie), GFP_KERNEL);
if (!ar_ie) {
ret = -ENOMEM;
goto done;
}
ar_ie->ie_index = cpu_to_le16(priv->assocresp_idx);
ar_ie->mgmt_subtype_mask = cpu_to_le16(MWIFIEX_DELETE_MASK);
ar_ie->ie_length = 0;
}
if (beacon_ie || pr_ie || ar_ie)
ret = mwifiex_update_uap_custom_ie(priv,
beacon_ie, &priv->beacon_idx,
pr_ie, &priv->proberesp_idx,
ar_ie, &priv->assocresp_idx);
done:
kfree(beacon_ie);
kfree(pr_ie);
kfree(ar_ie);
kfree(rsn_ie);
return ret;
}

View File

@ -279,6 +279,7 @@ static void mwifiex_init_adapter(struct mwifiex_adapter *adapter)
memset(&adapter->arp_filter, 0, sizeof(adapter->arp_filter));
adapter->arp_filter_size = 0;
adapter->channel_type = NL80211_CHAN_HT20;
adapter->max_mgmt_ie_index = MAX_MGMT_IE_INDEX;
}
/*

View File

@ -62,6 +62,36 @@ enum {
BAND_AN = 16,
};
#define MWIFIEX_WPA_PASSHPHRASE_LEN 64
struct wpa_param {
u8 pairwise_cipher_wpa;
u8 pairwise_cipher_wpa2;
u8 group_cipher;
u32 length;
u8 passphrase[MWIFIEX_WPA_PASSHPHRASE_LEN];
};
#define KEY_MGMT_ON_HOST 0x03
#define MWIFIEX_AUTH_MODE_AUTO 0xFF
#define BAND_CONFIG_MANUAL 0x00
struct mwifiex_uap_bss_param {
u8 channel;
u8 band_cfg;
u16 rts_threshold;
u16 frag_threshold;
u8 retry_limit;
struct mwifiex_802_11_ssid ssid;
u8 bcast_ssid_ctl;
u8 radio_ctl;
u8 dtim_period;
u16 beacon_period;
u16 auth_mode;
u16 protocol;
u16 key_mgmt;
u16 key_mgmt_operation;
struct wpa_param wpa_cfg;
};
enum {
ADHOC_IDLE,
ADHOC_STARTED,
@ -269,6 +299,8 @@ struct mwifiex_ds_read_eeprom {
#define IEEE_MAX_IE_SIZE 256
#define MWIFIEX_IE_HDR_SIZE (sizeof(struct mwifiex_ie) - IEEE_MAX_IE_SIZE)
struct mwifiex_ds_misc_gen_ie {
u32 type;
u32 len;

View File

@ -1374,22 +1374,28 @@ static int mwifiex_deauthenticate_infra(struct mwifiex_private *priv, u8 *mac)
*
* In case of infra made, it sends deauthentication request, and
* in case of ad-hoc mode, a stop network request is sent to the firmware.
* In AP mode, a command to stop bss is sent to firmware.
*/
int mwifiex_deauthenticate(struct mwifiex_private *priv, u8 *mac)
{
int ret = 0;
if (!priv->media_connected)
return 0;
if (priv->media_connected) {
if (priv->bss_mode == NL80211_IFTYPE_STATION) {
ret = mwifiex_deauthenticate_infra(priv, mac);
} else if (priv->bss_mode == NL80211_IFTYPE_ADHOC) {
ret = mwifiex_send_cmd_sync(priv,
HostCmd_CMD_802_11_AD_HOC_STOP,
HostCmd_ACT_GEN_SET, 0, NULL);
}
switch (priv->bss_mode) {
case NL80211_IFTYPE_STATION:
return mwifiex_deauthenticate_infra(priv, mac);
case NL80211_IFTYPE_ADHOC:
return mwifiex_send_cmd_sync(priv,
HostCmd_CMD_802_11_AD_HOC_STOP,
HostCmd_ACT_GEN_SET, 0, NULL);
case NL80211_IFTYPE_AP:
return mwifiex_send_cmd_sync(priv, HostCmd_CMD_UAP_BSS_STOP,
HostCmd_ACT_GEN_SET, 0, NULL);
default:
break;
}
return ret;
return 0;
}
EXPORT_SYMBOL_GPL(mwifiex_deauthenticate);

View File

@ -64,17 +64,17 @@ static int mwifiex_register(void *card, struct mwifiex_if_ops *if_ops,
adapter->priv_num = 0;
/* Allocate memory for private structure */
adapter->priv[0] = kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL);
if (!adapter->priv[0]) {
dev_err(adapter->dev,
"%s: failed to alloc priv[0]\n", __func__);
goto error;
for (i = 0; i < MWIFIEX_MAX_BSS_NUM; i++) {
/* Allocate memory for private structure */
adapter->priv[i] =
kzalloc(sizeof(struct mwifiex_private), GFP_KERNEL);
if (!adapter->priv[i])
goto error;
adapter->priv[i]->adapter = adapter;
adapter->priv[i]->bss_priority = i;
adapter->priv_num++;
}
adapter->priv_num++;
adapter->priv[0]->adapter = adapter;
mwifiex_init_lock_list(adapter);
init_timer(&adapter->cmd_timer);
@ -349,19 +349,26 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
if (adapter->hw_status != MWIFIEX_HW_STATUS_READY)
goto done;
priv = adapter->priv[0];
if (mwifiex_register_cfg80211(priv) != 0) {
priv = adapter->priv[MWIFIEX_BSS_ROLE_STA];
if (mwifiex_register_cfg80211(adapter)) {
dev_err(adapter->dev, "cannot register with cfg80211\n");
goto err_init_fw;
}
rtnl_lock();
/* Create station interface by default */
if (!mwifiex_add_virtual_intf(priv->wdev->wiphy, "mlan%d",
if (!mwifiex_add_virtual_intf(adapter->wiphy, "mlan%d",
NL80211_IFTYPE_STATION, NULL, NULL)) {
dev_err(adapter->dev, "cannot create default STA interface\n");
goto err_add_intf;
}
/* Create AP interface by default */
if (!mwifiex_add_virtual_intf(adapter->wiphy, "uap%d",
NL80211_IFTYPE_AP, NULL, NULL)) {
dev_err(adapter->dev, "cannot create default AP interface\n");
goto err_add_intf;
}
rtnl_unlock();
mwifiex_drv_get_driver_version(adapter, fmt, sizeof(fmt) - 1);
@ -369,7 +376,7 @@ static void mwifiex_fw_dpc(const struct firmware *firmware, void *context)
goto done;
err_add_intf:
mwifiex_del_virtual_intf(priv->wdev->wiphy, priv->netdev);
mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev);
rtnl_unlock();
err_init_fw:
pr_debug("info: %s: unregister device\n", __func__);
@ -633,6 +640,12 @@ void mwifiex_init_priv_params(struct mwifiex_private *priv,
priv->current_key_index = 0;
priv->media_connected = false;
memset(&priv->nick_name, 0, sizeof(priv->nick_name));
memset(priv->mgmt_ie, 0,
sizeof(struct mwifiex_ie) * MAX_MGMT_IE_INDEX);
priv->beacon_idx = MWIFIEX_AUTO_IDX_MASK;
priv->proberesp_idx = MWIFIEX_AUTO_IDX_MASK;
priv->assocresp_idx = MWIFIEX_AUTO_IDX_MASK;
priv->rsn_idx = MWIFIEX_AUTO_IDX_MASK;
priv->num_tx_timeout = 0;
memcpy(dev->dev_addr, priv->curr_addr, ETH_ALEN);
}
@ -830,19 +843,21 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
rtnl_lock();
if (priv->wdev && priv->netdev)
mwifiex_del_virtual_intf(priv->wdev->wiphy,
priv->netdev);
mwifiex_del_virtual_intf(adapter->wiphy, priv->netdev);
rtnl_unlock();
}
priv = adapter->priv[0];
if (!priv)
if (!priv || !priv->wdev)
goto exit_remove;
if (priv->wdev) {
wiphy_unregister(priv->wdev->wiphy);
wiphy_free(priv->wdev->wiphy);
kfree(priv->wdev);
wiphy_unregister(priv->wdev->wiphy);
wiphy_free(priv->wdev->wiphy);
for (i = 0; i < adapter->priv_num; i++) {
priv = adapter->priv[i];
if (priv)
kfree(priv->wdev);
}
mwifiex_terminate_workqueue(adapter);

View File

@ -116,6 +116,7 @@ enum {
#define MAX_FREQUENCY_BAND_BG 2484
#define MWIFIEX_EVENT_HEADER_LEN 4
#define MWIFIEX_UAP_EVENT_EXTRA_HEADER 2
#define MWIFIEX_TYPE_LEN 4
#define MWIFIEX_USB_TYPE_CMD 0xF00DFACE
@ -370,6 +371,7 @@ struct mwifiex_private {
u8 bss_role;
u8 bss_priority;
u8 bss_num;
u8 bss_started;
u8 frame_type;
u8 curr_addr[ETH_ALEN];
u8 media_connected;
@ -470,12 +472,16 @@ struct mwifiex_private {
struct cfg80211_scan_request *scan_request;
struct mwifiex_user_scan_cfg *user_scan_cfg;
u8 cfg_bssid[6];
u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
struct wps wps;
u8 scan_block;
s32 cqm_rssi_thold;
u32 cqm_rssi_hyst;
u8 subsc_evt_rssi_state;
struct mwifiex_ie mgmt_ie[MAX_MGMT_IE_INDEX];
u16 beacon_idx;
u16 proberesp_idx;
u16 assocresp_idx;
u16 rsn_idx;
};
enum mwifiex_ba_status {
@ -571,6 +577,7 @@ struct mwifiex_adapter {
char fw_name[32];
int winner;
struct device *dev;
struct wiphy *wiphy;
bool surprise_removed;
u32 fw_release_number;
u16 init_wait_q_woken;
@ -677,6 +684,8 @@ struct mwifiex_adapter {
struct cmd_ctrl_node *cmd_queued;
spinlock_t queue_lock; /* lock for tx queues */
struct completion fw_load;
u8 country_code[IEEE80211_COUNTRY_STRING_LEN];
u16 max_mgmt_ie_index;
};
int mwifiex_init_lock_list(struct mwifiex_adapter *adapter);
@ -760,6 +769,9 @@ int mwifiex_process_rx_packet(struct mwifiex_adapter *adapter,
int mwifiex_sta_prepare_cmd(struct mwifiex_private *, uint16_t cmd_no,
u16 cmd_action, u32 cmd_oid,
void *data_buf, void *cmd_buf);
int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, uint16_t cmd_no,
u16 cmd_action, u32 cmd_oid,
void *data_buf, void *cmd_buf);
int mwifiex_process_sta_cmdresp(struct mwifiex_private *, u16 cmdresp_no,
struct host_cmd_ds_command *resp);
int mwifiex_process_sta_rx_packet(struct mwifiex_adapter *,
@ -820,6 +832,9 @@ int mwifiex_ret_get_hw_spec(struct mwifiex_private *priv,
int is_command_pending(struct mwifiex_adapter *adapter);
void mwifiex_init_priv_params(struct mwifiex_private *priv,
struct net_device *dev);
int mwifiex_set_secure_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_config,
struct cfg80211_ap_settings *params);
/*
* This function checks if the queuing is RA based or not.
@ -933,7 +948,8 @@ int mwifiex_set_radio(struct mwifiex_private *priv, u8 option);
int mwifiex_drv_change_adhoc_chan(struct mwifiex_private *priv, u16 channel);
int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
int key_len, u8 key_index, int disable);
int key_len, u8 key_index, const u8 *mac_addr,
int disable);
int mwifiex_set_gen_ie(struct mwifiex_private *priv, u8 *ie, int ie_len);
@ -969,6 +985,7 @@ int mwifiex_set_tx_power(struct mwifiex_private *priv,
int mwifiex_main_process(struct mwifiex_adapter *);
int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel);
int mwifiex_bss_set_channel(struct mwifiex_private *,
struct mwifiex_chan_freq_power *cfp);
int mwifiex_get_bss_info(struct mwifiex_private *,
@ -986,6 +1003,11 @@ struct net_device *mwifiex_add_virtual_intf(struct wiphy *wiphy,
u32 *flags, struct vif_params *params);
int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct net_device *dev);
void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config);
int mwifiex_set_mgmt_ies(struct mwifiex_private *priv,
struct cfg80211_ap_settings *params);
int mwifiex_del_mgmt_ies(struct mwifiex_private *priv);
u8 *mwifiex_11d_code_2_region(u8 code);
#ifdef CONFIG_DEBUG_FS

View File

@ -498,7 +498,8 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
{
struct host_cmd_ds_802_11_key_material *key_material =
&cmd->params.key_material;
u16 key_param_len = 0;
struct host_cmd_tlv_mac_addr *tlv_mac;
u16 key_param_len = 0, cmd_size;
int ret = 0;
const u8 bc_mac[] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
@ -614,11 +615,26 @@ mwifiex_cmd_802_11_key_material(struct mwifiex_private *priv,
cpu_to_le16((u16) enc_key->key_len +
KEYPARAMSET_FIXED_LEN);
key_param_len = (u16) (enc_key->key_len + KEYPARAMSET_FIXED_LEN)
key_param_len = (u16)(enc_key->key_len + KEYPARAMSET_FIXED_LEN)
+ sizeof(struct mwifiex_ie_types_header);
cmd->size = cpu_to_le16(sizeof(key_material->action) + S_DS_GEN
+ key_param_len);
if (priv->bss_type == MWIFIEX_BSS_TYPE_UAP) {
tlv_mac = (void *)((u8 *)&key_material->key_param_set +
key_param_len);
tlv_mac->tlv.type = cpu_to_le16(TLV_TYPE_STA_MAC_ADDR);
tlv_mac->tlv.len = cpu_to_le16(ETH_ALEN);
memcpy(tlv_mac->mac_addr, enc_key->mac_addr, ETH_ALEN);
cmd_size = key_param_len + S_DS_GEN +
sizeof(key_material->action) +
sizeof(struct host_cmd_tlv_mac_addr);
} else {
cmd_size = key_param_len + S_DS_GEN +
sizeof(key_material->action);
}
cmd->size = cpu_to_le16(cmd_size);
}
return ret;
@ -1248,13 +1264,15 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;
/* Enable IEEE PS by default */
priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_802_11_PS_MODE_ENH,
EN_AUTO_PS, BITMAP_STA_PS, NULL);
if (ret)
return -1;
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
/* Enable IEEE PS by default */
priv->adapter->ps_mode = MWIFIEX_802_11_POWER_MODE_PSP;
ret = mwifiex_send_cmd_async(
priv, HostCmd_CMD_802_11_PS_MODE_ENH,
EN_AUTO_PS, BITMAP_STA_PS, NULL);
if (ret)
return -1;
}
}
/* get tx rate */
@ -1270,12 +1288,14 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;
/* set ibss coalescing_status */
ret = mwifiex_send_cmd_async(priv,
HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
HostCmd_ACT_GEN_SET, 0, &enable);
if (ret)
return -1;
if (priv->bss_type == MWIFIEX_BSS_TYPE_STA) {
/* set ibss coalescing_status */
ret = mwifiex_send_cmd_async(
priv, HostCmd_CMD_802_11_IBSS_COALESCING_STATUS,
HostCmd_ACT_GEN_SET, 0, &enable);
if (ret)
return -1;
}
memset(&amsdu_aggr_ctrl, 0, sizeof(amsdu_aggr_ctrl));
amsdu_aggr_ctrl.enable = true;
@ -1293,7 +1313,8 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
if (ret)
return -1;
if (first_sta && (priv->adapter->iface_type != MWIFIEX_USB)) {
if (first_sta && priv->adapter->iface_type != MWIFIEX_USB &&
priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
/* Enable auto deep sleep */
auto_ds.auto_ds = DEEP_SLEEP_ON;
auto_ds.idle_time = DEEP_SLEEP_IDLE_TIME;
@ -1305,12 +1326,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta)
return -1;
}
/* Send cmd to FW to enable/disable 11D function */
state_11d = ENABLE_11D;
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, DOT11D_I, &state_11d);
if (ret)
dev_err(priv->adapter->dev, "11D: failed to enable 11D\n");
if (priv->bss_type != MWIFIEX_BSS_TYPE_UAP) {
/* Send cmd to FW to enable/disable 11D function */
state_11d = ENABLE_11D;
ret = mwifiex_send_cmd_async(priv, HostCmd_CMD_802_11_SNMP_MIB,
HostCmd_ACT_GEN_SET, DOT11D_I,
&state_11d);
if (ret)
dev_err(priv->adapter->dev,
"11D: failed to enable 11D\n");
}
/* Send cmd to FW to configure 11n specific configuration
* (Short GI, Channel BW, Green field support etc.) for transmit

View File

@ -944,6 +944,14 @@ int mwifiex_process_sta_cmdresp(struct mwifiex_private *priv, u16 cmdresp_no,
case HostCmd_CMD_802_11_SUBSCRIBE_EVENT:
ret = mwifiex_ret_subsc_evt(priv, resp, data_buf);
break;
case HostCmd_CMD_UAP_SYS_CONFIG:
break;
case HostCmd_CMD_UAP_BSS_START:
priv->bss_started = 1;
break;
case HostCmd_CMD_UAP_BSS_STOP:
priv->bss_started = 0;
break;
default:
dev_err(adapter->dev, "CMD_RESP: unknown cmd response %#x\n",
resp->command);

View File

@ -184,8 +184,10 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv)
int mwifiex_process_sta_event(struct mwifiex_private *priv)
{
struct mwifiex_adapter *adapter = priv->adapter;
int ret = 0;
int len, ret = 0;
u32 eventcause = adapter->event_cause;
struct station_info sinfo;
struct mwifiex_assoc_event *event;
switch (eventcause) {
case EVENT_DUMMY_HOST_WAKEUP_SIGNAL:
@ -402,6 +404,53 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
case EVENT_HOSTWAKE_STAIE:
dev_dbg(adapter->dev, "event: HOSTWAKE_STAIE %d\n", eventcause);
break;
case EVENT_UAP_STA_ASSOC:
skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
memset(&sinfo, 0, sizeof(sinfo));
event = (struct mwifiex_assoc_event *)adapter->event_skb->data;
if (le16_to_cpu(event->type) == TLV_TYPE_UAP_MGMT_FRAME) {
len = -1;
if (ieee80211_is_assoc_req(event->frame_control))
len = 0;
else if (ieee80211_is_reassoc_req(event->frame_control))
/* There will be ETH_ALEN bytes of
* current_ap_addr before the re-assoc ies.
*/
len = ETH_ALEN;
if (len != -1) {
sinfo.filled = STATION_INFO_ASSOC_REQ_IES;
sinfo.assoc_req_ies = (u8 *)&event->data[len];
len = (u8 *)sinfo.assoc_req_ies -
(u8 *)&event->frame_control;
sinfo.assoc_req_ies_len =
le16_to_cpu(event->len) - (u16)len;
}
}
cfg80211_new_sta(priv->netdev, event->sta_addr, &sinfo,
GFP_KERNEL);
break;
case EVENT_UAP_STA_DEAUTH:
skb_pull(adapter->event_skb, MWIFIEX_UAP_EVENT_EXTRA_HEADER);
cfg80211_del_sta(priv->netdev, adapter->event_skb->data,
GFP_KERNEL);
break;
case EVENT_UAP_BSS_IDLE:
priv->media_connected = false;
break;
case EVENT_UAP_BSS_ACTIVE:
priv->media_connected = true;
break;
case EVENT_UAP_BSS_START:
dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
memcpy(priv->netdev->dev_addr, adapter->event_body+2, ETH_ALEN);
break;
case EVENT_UAP_MIC_COUNTERMEASURES:
/* For future development */
dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
break;
default:
dev_dbg(adapter->dev, "event: unknown event id: %#x\n",
eventcause);

View File

@ -462,7 +462,7 @@ int mwifiex_get_bss_info(struct mwifiex_private *priv,
info->bss_chan = bss_desc->channel;
memcpy(info->country_code, priv->country_code,
memcpy(info->country_code, adapter->country_code,
IEEE80211_COUNTRY_STRING_LEN);
info->media_connected = priv->media_connected;
@ -1219,7 +1219,8 @@ mwifiex_drv_get_driver_version(struct mwifiex_adapter *adapter, char *version,
* with requisite parameters and calls the IOCTL handler.
*/
int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
int key_len, u8 key_index, int disable)
int key_len, u8 key_index,
const u8 *mac_addr, int disable)
{
struct mwifiex_ds_encrypt_key encrypt_key;
@ -1229,8 +1230,12 @@ int mwifiex_set_encode(struct mwifiex_private *priv, const u8 *key,
encrypt_key.key_index = key_index;
if (key_len)
memcpy(encrypt_key.key_material, key, key_len);
if (mac_addr)
memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
} else {
encrypt_key.key_disable = true;
if (mac_addr)
memcpy(encrypt_key.mac_addr, mac_addr, ETH_ALEN);
}
return mwifiex_sec_ioctl_encrypt_key(priv, &encrypt_key);

View File

@ -0,0 +1,432 @@
/*
* Marvell Wireless LAN device driver: AP specific command handling
*
* Copyright (C) 2012, Marvell International Ltd.
*
* This software file (the "File") is distributed by Marvell International
* Ltd. under the terms of the GNU General Public License Version 2, June 1991
* (the "License"). You may use, redistribute and/or modify this File in
* accordance with the terms and conditions of the License, a copy of which
* is available by writing to the Free Software Foundation, Inc.,
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA or on the
* worldwide web at http://www.gnu.org/licenses/old-licenses/gpl-2.0.txt.
*
* THE FILE IS DISTRIBUTED AS-IS, WITHOUT WARRANTY OF ANY KIND, AND THE
* IMPLIED WARRANTIES OF MERCHANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE
* ARE EXPRESSLY DISCLAIMED. The License provides additional details about
* this warranty disclaimer.
*/
#include "main.h"
/* This function parses security related parameters from cfg80211_ap_settings
* and sets into FW understandable bss_config structure.
*/
int mwifiex_set_secure_params(struct mwifiex_private *priv,
struct mwifiex_uap_bss_param *bss_config,
struct cfg80211_ap_settings *params) {
int i;
switch (params->auth_type) {
case NL80211_AUTHTYPE_OPEN_SYSTEM:
bss_config->auth_mode = WLAN_AUTH_OPEN;
break;
case NL80211_AUTHTYPE_SHARED_KEY:
bss_config->auth_mode = WLAN_AUTH_SHARED_KEY;
break;
case NL80211_AUTHTYPE_NETWORK_EAP:
bss_config->auth_mode = WLAN_AUTH_LEAP;
break;
default:
bss_config->auth_mode = MWIFIEX_AUTH_MODE_AUTO;
break;
}
bss_config->key_mgmt_operation |= KEY_MGMT_ON_HOST;
for (i = 0; i < params->crypto.n_akm_suites; i++) {
switch (params->crypto.akm_suites[i]) {
case WLAN_AKM_SUITE_8021X:
if (params->crypto.wpa_versions &
NL80211_WPA_VERSION_1) {
bss_config->protocol = PROTOCOL_WPA;
bss_config->key_mgmt = KEY_MGMT_EAP;
}
if (params->crypto.wpa_versions &
NL80211_WPA_VERSION_2) {
bss_config->protocol = PROTOCOL_WPA2;
bss_config->key_mgmt = KEY_MGMT_EAP;
}
break;
case WLAN_AKM_SUITE_PSK:
if (params->crypto.wpa_versions &
NL80211_WPA_VERSION_1) {
bss_config->protocol = PROTOCOL_WPA;
bss_config->key_mgmt = KEY_MGMT_PSK;
}
if (params->crypto.wpa_versions &
NL80211_WPA_VERSION_2) {
bss_config->protocol = PROTOCOL_WPA2;
bss_config->key_mgmt = KEY_MGMT_PSK;
}
break;
default:
break;
}
}
for (i = 0; i < params->crypto.n_ciphers_pairwise; i++) {
switch (params->crypto.ciphers_pairwise[i]) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
break;
case WLAN_CIPHER_SUITE_TKIP:
bss_config->wpa_cfg.pairwise_cipher_wpa = CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
bss_config->wpa_cfg.pairwise_cipher_wpa2 =
CIPHER_AES_CCMP;
default:
break;
}
}
switch (params->crypto.cipher_group) {
case WLAN_CIPHER_SUITE_WEP40:
case WLAN_CIPHER_SUITE_WEP104:
break;
case WLAN_CIPHER_SUITE_TKIP:
bss_config->wpa_cfg.group_cipher = CIPHER_TKIP;
break;
case WLAN_CIPHER_SUITE_CCMP:
bss_config->wpa_cfg.group_cipher = CIPHER_AES_CCMP;
break;
default:
break;
}
return 0;
}
/* This function initializes some of mwifiex_uap_bss_param variables.
* This helps FW in ignoring invalid values. These values may or may not
* be get updated to valid ones at later stage.
*/
void mwifiex_set_sys_config_invalid_data(struct mwifiex_uap_bss_param *config)
{
config->bcast_ssid_ctl = 0x7F;
config->radio_ctl = 0x7F;
config->dtim_period = 0x7F;
config->beacon_period = 0x7FFF;
config->auth_mode = 0x7F;
config->rts_threshold = 0x7FFF;
config->frag_threshold = 0x7FFF;
config->retry_limit = 0x7F;
}
/* This function parses BSS related parameters from structure
* and prepares TLVs. These TLVs are appended to command buffer.
*/
static int
mwifiex_uap_bss_param_prepare(u8 *tlv, void *cmd_buf, u16 *param_size)
{
struct host_cmd_tlv_dtim_period *dtim_period;
struct host_cmd_tlv_beacon_period *beacon_period;
struct host_cmd_tlv_ssid *ssid;
struct host_cmd_tlv_channel_band *chan_band;
struct host_cmd_tlv_frag_threshold *frag_threshold;
struct host_cmd_tlv_rts_threshold *rts_threshold;
struct host_cmd_tlv_retry_limit *retry_limit;
struct host_cmd_tlv_pwk_cipher *pwk_cipher;
struct host_cmd_tlv_gwk_cipher *gwk_cipher;
struct host_cmd_tlv_encrypt_protocol *encrypt_protocol;
struct host_cmd_tlv_auth_type *auth_type;
struct host_cmd_tlv_passphrase *passphrase;
struct host_cmd_tlv_akmp *tlv_akmp;
struct mwifiex_uap_bss_param *bss_cfg = cmd_buf;
u16 cmd_size = *param_size;
if (bss_cfg->ssid.ssid_len) {
ssid = (struct host_cmd_tlv_ssid *)tlv;
ssid->tlv.type = cpu_to_le16(TLV_TYPE_UAP_SSID);
ssid->tlv.len = cpu_to_le16((u16)bss_cfg->ssid.ssid_len);
memcpy(ssid->ssid, bss_cfg->ssid.ssid, bss_cfg->ssid.ssid_len);
cmd_size += sizeof(struct host_cmd_tlv) +
bss_cfg->ssid.ssid_len;
tlv += sizeof(struct host_cmd_tlv) + bss_cfg->ssid.ssid_len;
}
if (bss_cfg->channel && bss_cfg->channel <= MAX_CHANNEL_BAND_BG) {
chan_band = (struct host_cmd_tlv_channel_band *)tlv;
chan_band->tlv.type = cpu_to_le16(TLV_TYPE_CHANNELBANDLIST);
chan_band->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_channel_band) -
sizeof(struct host_cmd_tlv));
chan_band->band_config = bss_cfg->band_cfg;
chan_band->channel = bss_cfg->channel;
cmd_size += sizeof(struct host_cmd_tlv_channel_band);
tlv += sizeof(struct host_cmd_tlv_channel_band);
}
if (bss_cfg->beacon_period >= MIN_BEACON_PERIOD &&
bss_cfg->beacon_period <= MAX_BEACON_PERIOD) {
beacon_period = (struct host_cmd_tlv_beacon_period *)tlv;
beacon_period->tlv.type =
cpu_to_le16(TLV_TYPE_UAP_BEACON_PERIOD);
beacon_period->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_beacon_period) -
sizeof(struct host_cmd_tlv));
beacon_period->period = cpu_to_le16(bss_cfg->beacon_period);
cmd_size += sizeof(struct host_cmd_tlv_beacon_period);
tlv += sizeof(struct host_cmd_tlv_beacon_period);
}
if (bss_cfg->dtim_period >= MIN_DTIM_PERIOD &&
bss_cfg->dtim_period <= MAX_DTIM_PERIOD) {
dtim_period = (struct host_cmd_tlv_dtim_period *)tlv;
dtim_period->tlv.type = cpu_to_le16(TLV_TYPE_UAP_DTIM_PERIOD);
dtim_period->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_dtim_period) -
sizeof(struct host_cmd_tlv));
dtim_period->period = bss_cfg->dtim_period;
cmd_size += sizeof(struct host_cmd_tlv_dtim_period);
tlv += sizeof(struct host_cmd_tlv_dtim_period);
}
if (bss_cfg->rts_threshold <= MWIFIEX_RTS_MAX_VALUE) {
rts_threshold = (struct host_cmd_tlv_rts_threshold *)tlv;
rts_threshold->tlv.type =
cpu_to_le16(TLV_TYPE_UAP_RTS_THRESHOLD);
rts_threshold->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_rts_threshold) -
sizeof(struct host_cmd_tlv));
rts_threshold->rts_thr = cpu_to_le16(bss_cfg->rts_threshold);
cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
tlv += sizeof(struct host_cmd_tlv_frag_threshold);
}
if ((bss_cfg->frag_threshold >= MWIFIEX_FRAG_MIN_VALUE) &&
(bss_cfg->frag_threshold <= MWIFIEX_FRAG_MAX_VALUE)) {
frag_threshold = (struct host_cmd_tlv_frag_threshold *)tlv;
frag_threshold->tlv.type =
cpu_to_le16(TLV_TYPE_UAP_FRAG_THRESHOLD);
frag_threshold->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_frag_threshold) -
sizeof(struct host_cmd_tlv));
frag_threshold->frag_thr = cpu_to_le16(bss_cfg->frag_threshold);
cmd_size += sizeof(struct host_cmd_tlv_frag_threshold);
tlv += sizeof(struct host_cmd_tlv_frag_threshold);
}
if (bss_cfg->retry_limit <= MWIFIEX_RETRY_LIMIT) {
retry_limit = (struct host_cmd_tlv_retry_limit *)tlv;
retry_limit->tlv.type = cpu_to_le16(TLV_TYPE_UAP_RETRY_LIMIT);
retry_limit->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_retry_limit) -
sizeof(struct host_cmd_tlv));
retry_limit->limit = (u8)bss_cfg->retry_limit;
cmd_size += sizeof(struct host_cmd_tlv_retry_limit);
tlv += sizeof(struct host_cmd_tlv_retry_limit);
}
if ((bss_cfg->protocol & PROTOCOL_WPA) ||
(bss_cfg->protocol & PROTOCOL_WPA2) ||
(bss_cfg->protocol & PROTOCOL_EAP)) {
tlv_akmp = (struct host_cmd_tlv_akmp *)tlv;
tlv_akmp->tlv.type = cpu_to_le16(TLV_TYPE_UAP_AKMP);
tlv_akmp->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_akmp) -
sizeof(struct host_cmd_tlv));
tlv_akmp->key_mgmt_operation =
cpu_to_le16(bss_cfg->key_mgmt_operation);
tlv_akmp->key_mgmt = cpu_to_le16(bss_cfg->key_mgmt);
cmd_size += sizeof(struct host_cmd_tlv_akmp);
tlv += sizeof(struct host_cmd_tlv_akmp);
if (bss_cfg->wpa_cfg.pairwise_cipher_wpa &
VALID_CIPHER_BITMAP) {
pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
pwk_cipher->tlv.type =
cpu_to_le16(TLV_TYPE_PWK_CIPHER);
pwk_cipher->tlv.len = cpu_to_le16(
sizeof(struct host_cmd_tlv_pwk_cipher) -
sizeof(struct host_cmd_tlv));
pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA);
pwk_cipher->cipher =
bss_cfg->wpa_cfg.pairwise_cipher_wpa;
cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
}
if (bss_cfg->wpa_cfg.pairwise_cipher_wpa2 &
VALID_CIPHER_BITMAP) {
pwk_cipher = (struct host_cmd_tlv_pwk_cipher *)tlv;
pwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_PWK_CIPHER);
pwk_cipher->tlv.len = cpu_to_le16(
sizeof(struct host_cmd_tlv_pwk_cipher) -
sizeof(struct host_cmd_tlv));
pwk_cipher->proto = cpu_to_le16(PROTOCOL_WPA2);
pwk_cipher->cipher =
bss_cfg->wpa_cfg.pairwise_cipher_wpa2;
cmd_size += sizeof(struct host_cmd_tlv_pwk_cipher);
tlv += sizeof(struct host_cmd_tlv_pwk_cipher);
}
if (bss_cfg->wpa_cfg.group_cipher & VALID_CIPHER_BITMAP) {
gwk_cipher = (struct host_cmd_tlv_gwk_cipher *)tlv;
gwk_cipher->tlv.type = cpu_to_le16(TLV_TYPE_GWK_CIPHER);
gwk_cipher->tlv.len = cpu_to_le16(
sizeof(struct host_cmd_tlv_gwk_cipher) -
sizeof(struct host_cmd_tlv));
gwk_cipher->cipher = bss_cfg->wpa_cfg.group_cipher;
cmd_size += sizeof(struct host_cmd_tlv_gwk_cipher);
tlv += sizeof(struct host_cmd_tlv_gwk_cipher);
}
if (bss_cfg->wpa_cfg.length) {
passphrase = (struct host_cmd_tlv_passphrase *)tlv;
passphrase->tlv.type =
cpu_to_le16(TLV_TYPE_UAP_WPA_PASSPHRASE);
passphrase->tlv.len =
cpu_to_le16(bss_cfg->wpa_cfg.length);
memcpy(passphrase->passphrase,
bss_cfg->wpa_cfg.passphrase,
bss_cfg->wpa_cfg.length);
cmd_size += sizeof(struct host_cmd_tlv) +
bss_cfg->wpa_cfg.length;
tlv += sizeof(struct host_cmd_tlv) +
bss_cfg->wpa_cfg.length;
}
}
if ((bss_cfg->auth_mode <= WLAN_AUTH_SHARED_KEY) ||
(bss_cfg->auth_mode == MWIFIEX_AUTH_MODE_AUTO)) {
auth_type = (struct host_cmd_tlv_auth_type *)tlv;
auth_type->tlv.type = cpu_to_le16(TLV_TYPE_AUTH_TYPE);
auth_type->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_auth_type) -
sizeof(struct host_cmd_tlv));
auth_type->auth_type = (u8)bss_cfg->auth_mode;
cmd_size += sizeof(struct host_cmd_tlv_auth_type);
tlv += sizeof(struct host_cmd_tlv_auth_type);
}
if (bss_cfg->protocol) {
encrypt_protocol = (struct host_cmd_tlv_encrypt_protocol *)tlv;
encrypt_protocol->tlv.type =
cpu_to_le16(TLV_TYPE_UAP_ENCRY_PROTOCOL);
encrypt_protocol->tlv.len =
cpu_to_le16(sizeof(struct host_cmd_tlv_encrypt_protocol)
- sizeof(struct host_cmd_tlv));
encrypt_protocol->proto = cpu_to_le16(bss_cfg->protocol);
cmd_size += sizeof(struct host_cmd_tlv_encrypt_protocol);
tlv += sizeof(struct host_cmd_tlv_encrypt_protocol);
}
*param_size = cmd_size;
return 0;
}
/* This function parses custom IEs from IE list and prepares command buffer */
static int mwifiex_uap_custom_ie_prepare(u8 *tlv, void *cmd_buf, u16 *ie_size)
{
struct mwifiex_ie_list *ap_ie = cmd_buf;
struct host_cmd_tlv *tlv_ie = (struct host_cmd_tlv *)tlv;
if (!ap_ie || !ap_ie->len || !ap_ie->ie_list)
return -1;
*ie_size += le16_to_cpu(ap_ie->len) + sizeof(struct host_cmd_tlv);
tlv_ie->type = cpu_to_le16(TLV_TYPE_MGMT_IE);
tlv_ie->len = ap_ie->len;
tlv += sizeof(struct host_cmd_tlv);
memcpy(tlv, ap_ie->ie_list, le16_to_cpu(ap_ie->len));
return 0;
}
/* Parse AP config structure and prepare TLV based command structure
* to be sent to FW for uAP configuration
*/
static int
mwifiex_cmd_uap_sys_config(struct host_cmd_ds_command *cmd, u16 cmd_action,
u32 type, void *cmd_buf)
{
u8 *tlv;
u16 cmd_size, param_size, ie_size;
struct host_cmd_ds_sys_config *sys_cfg;
cmd->command = cpu_to_le16(HostCmd_CMD_UAP_SYS_CONFIG);
cmd_size = (u16)(sizeof(struct host_cmd_ds_sys_config) + S_DS_GEN);
sys_cfg = (struct host_cmd_ds_sys_config *)&cmd->params.uap_sys_config;
sys_cfg->action = cpu_to_le16(cmd_action);
tlv = sys_cfg->tlv;
switch (type) {
case UAP_BSS_PARAMS_I:
param_size = cmd_size;
if (mwifiex_uap_bss_param_prepare(tlv, cmd_buf, &param_size))
return -1;
cmd->size = cpu_to_le16(param_size);
break;
case UAP_CUSTOM_IE_I:
ie_size = cmd_size;
if (mwifiex_uap_custom_ie_prepare(tlv, cmd_buf, &ie_size))
return -1;
cmd->size = cpu_to_le16(ie_size);
break;
default:
return -1;
}
return 0;
}
/* This function prepares the AP specific commands before sending them
* to the firmware.
* This is a generic function which calls specific command preparation
* routines based upon the command number.
*/
int mwifiex_uap_prepare_cmd(struct mwifiex_private *priv, u16 cmd_no,
u16 cmd_action, u32 type,
void *data_buf, void *cmd_buf)
{
struct host_cmd_ds_command *cmd = cmd_buf;
switch (cmd_no) {
case HostCmd_CMD_UAP_SYS_CONFIG:
if (mwifiex_cmd_uap_sys_config(cmd, cmd_action, type, data_buf))
return -1;
break;
case HostCmd_CMD_UAP_BSS_START:
case HostCmd_CMD_UAP_BSS_STOP:
cmd->command = cpu_to_le16(cmd_no);
cmd->size = cpu_to_le16(S_DS_GEN);
break;
default:
dev_err(priv->adapter->dev,
"PREP_CMD: unknown cmd %#x\n", cmd_no);
return -1;
}
return 0;
}
/* This function sets the RF channel for AP.
*
* This function populates channel information in AP config structure
* and sends command to configure channel information in AP.
*/
int mwifiex_uap_set_channel(struct mwifiex_private *priv, int channel)
{
struct mwifiex_uap_bss_param *bss_cfg;
struct wiphy *wiphy = priv->wdev->wiphy;
bss_cfg = kzalloc(sizeof(struct mwifiex_uap_bss_param), GFP_KERNEL);
if (!bss_cfg)
return -ENOMEM;
bss_cfg->band_cfg = BAND_CONFIG_MANUAL;
bss_cfg->channel = channel;
if (mwifiex_send_cmd_async(priv, HostCmd_CMD_UAP_SYS_CONFIG,
HostCmd_ACT_GEN_SET,
UAP_BSS_PARAMS_I, bss_cfg)) {
wiphy_err(wiphy, "Failed to set the uAP channel\n");
kfree(bss_cfg);
return -1;
}
kfree(bss_cfg);
return 0;
}

View File

@ -885,6 +885,10 @@ mwifiex_wmm_get_highest_priolist_ptr(struct mwifiex_adapter *adapter,
tid_ptr = &(priv_tmp)->wmm.
tid_tbl_ptr[tos_to_tid[i]];
/* For non-STA ra_list_curr may be NULL */
if (!tid_ptr->ra_list_curr)
continue;
spin_lock_irqsave(&tid_ptr->tid_tbl_lock,
flags);
is_list_empty =

View File

@ -505,9 +505,6 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev);
static int rndis_set_channel(struct wiphy *wiphy, struct net_device *dev,
struct ieee80211_channel *chan, enum nl80211_channel_type channel_type);
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params);
@ -549,7 +546,6 @@ static const struct cfg80211_ops rndis_config_ops = {
.disconnect = rndis_disconnect,
.join_ibss = rndis_join_ibss,
.leave_ibss = rndis_leave_ibss,
.set_channel = rndis_set_channel,
.add_key = rndis_add_key,
.del_key = rndis_del_key,
.set_default_key = rndis_set_default_key,
@ -2398,16 +2394,6 @@ static int rndis_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
return deauthenticate(usbdev);
}
static int rndis_set_channel(struct wiphy *wiphy, struct net_device *netdev,
struct ieee80211_channel *chan, enum nl80211_channel_type channel_type)
{
struct rndis_wlan_private *priv = wiphy_priv(wiphy);
struct usbnet *usbdev = priv->usbdev;
return set_channel(usbdev,
ieee80211_frequency_to_channel(chan->center_freq));
}
static int rndis_add_key(struct wiphy *wiphy, struct net_device *netdev,
u8 key_index, bool pairwise, const u8 *mac_addr,
struct key_params *params)

View File

@ -1192,6 +1192,7 @@ static DEFINE_PCI_DEVICE_TABLE(rt2800pci_device_table) = {
{ PCI_DEVICE(0x1814, 0x5390) },
{ PCI_DEVICE(0x1814, 0x5392) },
{ PCI_DEVICE(0x1814, 0x539a) },
{ PCI_DEVICE(0x1814, 0x539b) },
{ PCI_DEVICE(0x1814, 0x539f) },
#endif
{ 0, }

View File

@ -1,5 +1,6 @@
config WL12XX
tristate "TI wl12xx support"
depends on MAC80211
select WLCORE
---help---
This module adds support for wireless adapters based on TI wl1271,

View File

@ -1,6 +1,6 @@
config WLCORE
tristate "TI wlcore support"
depends on WL_TI && GENERIC_HARDIRQS
depends on WL_TI && GENERIC_HARDIRQS && MAC80211
depends on INET
select FW_LOADER
---help---

View File

@ -1714,3 +1714,83 @@ out:
return ret;
}
/* Set the global behaviour of RX filters - On/Off + default action */
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
enum rx_filter_action action)
{
struct acx_default_rx_filter *acx;
int ret;
wl1271_debug(DEBUG_ACX, "acx default rx filter en: %d act: %d",
enable, action);
acx = kzalloc(sizeof(*acx), GFP_KERNEL);
if (!acx)
return -ENOMEM;
acx->enable = enable;
acx->default_action = action;
ret = wl1271_cmd_configure(wl, ACX_ENABLE_RX_DATA_FILTER, acx,
sizeof(*acx));
if (ret < 0) {
wl1271_warning("acx default rx filter enable failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}
/* Configure or disable a specific RX filter pattern */
int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable,
struct wl12xx_rx_filter *filter)
{
struct acx_rx_filter_cfg *acx;
int fields_size = 0;
int acx_size;
int ret;
WARN_ON(enable && !filter);
WARN_ON(index >= WL1271_MAX_RX_FILTERS);
wl1271_debug(DEBUG_ACX,
"acx set rx filter idx: %d enable: %d filter: %p",
index, enable, filter);
if (enable) {
fields_size = wl1271_rx_filter_get_fields_size(filter);
wl1271_debug(DEBUG_ACX, "act: %d num_fields: %d field_size: %d",
filter->action, filter->num_fields, fields_size);
}
acx_size = ALIGN(sizeof(*acx) + fields_size, 4);
acx = kzalloc(acx_size, GFP_KERNEL);
if (!acx)
return -ENOMEM;
acx->enable = enable;
acx->index = index;
if (enable) {
acx->num_fields = filter->num_fields;
acx->action = filter->action;
wl1271_rx_filter_flatten_fields(filter, acx->fields);
}
wl1271_dump(DEBUG_ACX, "RX_FILTER: ", acx, acx_size);
ret = wl1271_cmd_configure(wl, ACX_SET_RX_DATA_FILTER, acx, acx_size);
if (ret < 0) {
wl1271_warning("setting rx filter failed: %d", ret);
goto out;
}
out:
kfree(acx);
return ret;
}

View File

@ -1147,6 +1147,32 @@ struct wl12xx_acx_config_hangover {
u8 padding[2];
} __packed;
struct acx_default_rx_filter {
struct acx_header header;
u8 enable;
/* action of type FILTER_XXX */
u8 default_action;
u8 pad[2];
} __packed;
struct acx_rx_filter_cfg {
struct acx_header header;
u8 enable;
/* 0 - WL1271_MAX_RX_FILTERS-1 */
u8 index;
u8 action;
u8 num_fields;
u8 fields[0];
} __packed;
enum {
ACX_WAKE_UP_CONDITIONS = 0x0000,
ACX_MEM_CFG = 0x0001,
@ -1304,5 +1330,9 @@ int wl1271_acx_set_inconnection_sta(struct wl1271 *wl, u8 *addr);
int wl1271_acx_fm_coex(struct wl1271 *wl);
int wl12xx_acx_set_rate_mgmt_params(struct wl1271 *wl);
int wl12xx_acx_config_hangover(struct wl1271 *wl);
int wl1271_acx_default_rx_filter_enable(struct wl1271 *wl, bool enable,
enum rx_filter_action action);
int wl1271_acx_set_rx_filter(struct wl1271 *wl, u8 index, bool enable,
struct wl12xx_rx_filter *filter);
#endif /* __WL1271_ACX_H__ */

Some files were not shown because too many files have changed in this diff Show More