Commit 921a678c authored by David S. Miller's avatar David S. Miller

Merge branch 'for-davem' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wireless-next

John Linville says:

====================
Several drivers see updates: mwifiex, ath9k, iwlwifi, brcmsmac,
wlcore/wl12xx/wl18xx, and a handful of others.  The bcma bus got a
lot of attention from Hauke Mehrtens.  The cfg80211 component gets
a flurry of patches for multi-channel support, and the mac80211
component gets the first few VHT (11ac) and 60GHz (11ad) patches.
This also includes the removal of the iwmc3200 drivers, since the
hardware never became available to normal people.

Additionally, the NFC subsystem gets a series of updates.  According to
Samuel, "Here are the interesting bits:

- A better error management for the HCI stack.
- An LLCP "late" binding implementation for a better NFC SAP usage. SAPs are
  now reserved only when there's a client for it.
- Support for Sony RC-S360 (a.k.a. PaSoRi) pn533 based dongle. We can read and
  write NFC tags and also establish a p2p link with this dongle now.
- A few LLCP fixes."

Finally, this includes another pull of the fixes from the wireless
tree in order to resolve some merge issues.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 85b91b03 38a00840
......@@ -178,3 +178,36 @@ ANY_GET_PARAMETER to the reader A gate to get information on the target
that was discovered).
Typically, such an event will be propagated to NFC Core from MSGRXWQ context.
Error management
----------------
Errors that occur synchronously with the execution of an NFC Core request are
simply returned as the execution result of the request. These are easy.
Errors that occur asynchronously (e.g. in a background protocol handling thread)
must be reported such that upper layers don't stay ignorant that something
went wrong below and know that expected events will probably never happen.
Handling of these errors is done as follows:
- driver (pn544) fails to deliver an incoming frame: it stores the error such
that any subsequent call to the driver will result in this error. Then it calls
the standard nfc_shdlc_recv_frame() with a NULL argument to report the problem
above. shdlc stores a EREMOTEIO sticky status, which will trigger SMW to
report above in turn.
- SMW is basically a background thread to handle incoming and outgoing shdlc
frames. This thread will also check the shdlc sticky status and report to HCI
when it discovers it is not able to run anymore because of an unrecoverable
error that happened within shdlc or below. If the problem occurs during shdlc
connection, the error is reported through the connect completion.
- HCI: if an internal HCI error happens (frame is lost), or HCI is reported an
error from a lower layer, HCI will either complete the currently executing
command with that error, or notify NFC Core directly if no command is executing.
- NFC Core: when NFC Core is notified of an error from below and polling is
active, it will send a tag discovered event with an empty tag list to the user
space to let it know that the poll operation will never be able to detect a tag.
If polling is not active and the error was sticky, lower levels will return it
at next invocation.
......@@ -3661,14 +3661,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/iwlwifi/iwlwifi.git
S: Supported
F: drivers/net/wireless/iwlwifi/
INTEL WIRELESS MULTICOMM 3200 WIFI (iwmc3200wifi)
M: Samuel Ortiz <samuel.ortiz@intel.com>
M: Intel Linux Wireless <ilw@linux.intel.com>
L: linux-wireless@vger.kernel.org
S: Supported
W: http://wireless.kernel.org/en/users/Drivers/iwmc3200wifi
F: drivers/net/wireless/iwmc3200wifi/
INTEL MANAGEMENT ENGINE (mei)
M: Tomas Winkler <tomas.winkler@intel.com>
L: linux-kernel@vger.kernel.org
......
......@@ -10,6 +10,15 @@
#define BCMA_CORE_SIZE 0x1000
#define bcma_err(bus, fmt, ...) \
pr_err("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
#define bcma_warn(bus, fmt, ...) \
pr_warn("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
#define bcma_info(bus, fmt, ...) \
pr_info("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
#define bcma_debug(bus, fmt, ...) \
pr_debug("bus%d: " fmt, (bus)->num, ##__VA_ARGS__)
struct bcma_bus;
/* main.c */
......
......@@ -75,7 +75,7 @@ void bcma_core_set_clockmode(struct bcma_device *core,
udelay(10);
}
if (i)
pr_err("HT force timeout\n");
bcma_err(core->bus, "HT force timeout\n");
break;
case BCMA_CLKMODE_DYNAMIC:
bcma_set32(core, BCMA_CLKCTLST, ~BCMA_CLKCTLST_FORCEHT);
......@@ -102,9 +102,9 @@ void bcma_core_pll_ctl(struct bcma_device *core, u32 req, u32 status, bool on)
udelay(10);
}
if (i)
pr_err("PLL enable timeout\n");
bcma_err(core->bus, "PLL enable timeout\n");
} else {
pr_warn("Disabling PLL not supported yet!\n");
bcma_warn(core->bus, "Disabling PLL not supported yet!\n");
}
}
EXPORT_SYMBOL_GPL(bcma_core_pll_ctl);
......@@ -120,8 +120,8 @@ u32 bcma_core_dma_translation(struct bcma_device *core)
else
return BCMA_DMA_TRANSLATION_DMA32_CMT;
default:
pr_err("DMA translation unknown for host %d\n",
core->bus->hosttype);
bcma_err(core->bus, "DMA translation unknown for host %d\n",
core->bus->hosttype);
}
return BCMA_DMA_TRANSLATION_NONE;
}
......
......@@ -44,7 +44,7 @@ void bcma_core_chipcommon_init(struct bcma_drv_cc *cc)
if (cc->capabilities & BCMA_CC_CAP_PMU)
bcma_pmu_init(cc);
if (cc->capabilities & BCMA_CC_CAP_PCTL)
pr_err("Power control not implemented!\n");
bcma_err(cc->core->bus, "Power control not implemented!\n");
if (cc->core->id.rev >= 16) {
if (cc->core->bus->sprom.leddc_on_time &&
......@@ -137,8 +137,7 @@ void bcma_chipco_serial_init(struct bcma_drv_cc *cc)
| BCMA_CC_CORECTL_UARTCLKEN);
}
} else {
pr_err("serial not supported on this device ccrev: 0x%x\n",
ccrev);
bcma_err(cc->core->bus, "serial not supported on this device ccrev: 0x%x\n", ccrev);
return;
}
......
This diff is collapsed.
......@@ -22,15 +22,15 @@
/* The 47162a0 hangs when reading MIPS DMP registers registers */
static inline bool bcma_core_mips_bcm47162a0_quirk(struct bcma_device *dev)
{
return dev->bus->chipinfo.id == 47162 && dev->bus->chipinfo.rev == 0 &&
dev->id.id == BCMA_CORE_MIPS_74K;
return dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM47162 &&
dev->bus->chipinfo.rev == 0 && dev->id.id == BCMA_CORE_MIPS_74K;
}
/* The 5357b0 hangs when reading USB20H DMP registers */
static inline bool bcma_core_mips_bcm5357b0_quirk(struct bcma_device *dev)
{
return (dev->bus->chipinfo.id == 0x5357 ||
dev->bus->chipinfo.id == 0x4749) &&
return (dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM5357 ||
dev->bus->chipinfo.id == BCMA_CHIP_ID_BCM4749) &&
dev->bus->chipinfo.pkg == 11 &&
dev->id.id == BCMA_CORE_USB20_HOST;
}
......@@ -143,8 +143,8 @@ static void bcma_core_mips_set_irq(struct bcma_device *dev, unsigned int irq)
1 << irqflag);
}
pr_info("set_irq: core 0x%04x, irq %d => %d\n",
dev->id.id, oldirq + 2, irq + 2);
bcma_info(bus, "set_irq: core 0x%04x, irq %d => %d\n",
dev->id.id, oldirq + 2, irq + 2);
}
static void bcma_core_mips_print_irq(struct bcma_device *dev, unsigned int irq)
......@@ -173,7 +173,7 @@ u32 bcma_cpu_clock(struct bcma_drv_mips *mcore)
if (bus->drv_cc.capabilities & BCMA_CC_CAP_PMU)
return bcma_pmu_get_clockcpu(&bus->drv_cc);
pr_err("No PMU available, need this to get the cpu clock\n");
bcma_err(bus, "No PMU available, need this to get the cpu clock\n");
return 0;
}
EXPORT_SYMBOL(bcma_cpu_clock);
......@@ -185,10 +185,10 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
switch (bus->drv_cc.capabilities & BCMA_CC_CAP_FLASHT) {
case BCMA_CC_FLASHT_STSER:
case BCMA_CC_FLASHT_ATSER:
pr_err("Serial flash not supported.\n");
bcma_err(bus, "Serial flash not supported.\n");
break;
case BCMA_CC_FLASHT_PARA:
pr_info("found parallel flash.\n");
bcma_info(bus, "found parallel flash.\n");
bus->drv_cc.pflash.window = 0x1c000000;
bus->drv_cc.pflash.window_size = 0x02000000;
......@@ -199,7 +199,7 @@ static void bcma_core_mips_flash_detect(struct bcma_drv_mips *mcore)
bus->drv_cc.pflash.buswidth = 2;
break;
default:
pr_err("flash not supported.\n");
bcma_err(bus, "flash not supported.\n");
}
}
......@@ -209,7 +209,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
struct bcma_device *core;
bus = mcore->core->bus;
pr_info("Initializing MIPS core...\n");
bcma_info(bus, "Initializing MIPS core...\n");
if (!mcore->setup_done)
mcore->assigned_irqs = 1;
......@@ -244,7 +244,7 @@ void bcma_core_mips_init(struct bcma_drv_mips *mcore)
break;
}
}
pr_info("IRQ reconfiguration done\n");
bcma_info(bus, "IRQ reconfiguration done\n");
bcma_core_mips_dump_irq(bus);
if (mcore->setup_done)
......
......@@ -36,7 +36,7 @@ bool __devinit bcma_core_pci_is_in_hostmode(struct bcma_drv_pci *pc)
return false;
if (bus->sprom.boardflags_lo & BCMA_CORE_PCI_BFL_NOPCI) {
pr_info("This PCI core is disabled and not working\n");
bcma_info(bus, "This PCI core is disabled and not working\n");
return false;
}
......@@ -215,7 +215,8 @@ static int bcma_extpci_write_config(struct bcma_drv_pci *pc, unsigned int dev,
} else {
writel(val, mmio);
if (chipid == 0x4716 || chipid == 0x4748)
if (chipid == BCMA_CHIP_ID_BCM4716 ||
chipid == BCMA_CHIP_ID_BCM4748)
readl(mmio);
}
......@@ -340,6 +341,7 @@ static u8 __devinit bcma_find_pci_capability(struct bcma_drv_pci *pc,
*/
static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc)
{
struct bcma_bus *bus = pc->core->bus;
u8 cap_ptr, root_ctrl, root_cap, dev;
u16 val16;
int i;
......@@ -378,7 +380,8 @@ static void __devinit bcma_core_pci_enable_crs(struct bcma_drv_pci *pc)
udelay(10);
}
if (val16 == 0x1)
pr_err("PCI: Broken device in slot %d\n", dev);
bcma_err(bus, "PCI: Broken device in slot %d\n",
dev);
}
}
}
......@@ -391,11 +394,11 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
u32 pci_membase_1G;
unsigned long io_map_base;
pr_info("PCIEcore in host mode found\n");
bcma_info(bus, "PCIEcore in host mode found\n");
pc_host = kzalloc(sizeof(*pc_host), GFP_KERNEL);
if (!pc_host) {
pr_err("can not allocate memory");
bcma_err(bus, "can not allocate memory");
return;
}
......@@ -434,13 +437,14 @@ void __devinit bcma_core_pci_hostmode_init(struct bcma_drv_pci *pc)
* as mips can't generate 64-bit address on the
* backplane.
*/
if (bus->chipinfo.id == 0x4716 || bus->chipinfo.id == 0x4748) {
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4716 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM4748) {
pc_host->mem_resource.start = BCMA_SOC_PCI_MEM;
pc_host->mem_resource.end = BCMA_SOC_PCI_MEM +
BCMA_SOC_PCI_MEM_SZ - 1;
pcicore_write32(pc, BCMA_CORE_PCI_SBTOPCI0,
BCMA_CORE_PCI_SBTOPCI_MEM | BCMA_SOC_PCI_MEM);
} else if (bus->chipinfo.id == 0x5300) {
} else if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4706) {
tmp = BCMA_CORE_PCI_SBTOPCI_MEM;
tmp |= BCMA_CORE_PCI_SBTOPCI_PREF;
tmp |= BCMA_CORE_PCI_SBTOPCI_BURST;
......
......@@ -18,7 +18,7 @@ static void bcma_host_pci_switch_core(struct bcma_device *core)
pci_write_config_dword(core->bus->host_pci, BCMA_PCI_BAR0_WIN2,
core->wrap);
core->bus->mapped_core = core;
pr_debug("Switched to core: 0x%X\n", core->id.id);
bcma_debug(core->bus, "Switched to core: 0x%X\n", core->id.id);
}
/* Provides access to the requested core. Returns base offset that has to be
......@@ -188,7 +188,7 @@ static int __devinit bcma_host_pci_probe(struct pci_dev *dev,
/* SSB needed additional powering up, do we have any AMBA PCI cards? */
if (!pci_is_pcie(dev))
pr_err("PCI card detected, report problems.\n");
bcma_err(bus, "PCI card detected, report problems.\n");
/* Map MMIO */
err = -ENOMEM;
......@@ -268,6 +268,7 @@ static SIMPLE_DEV_PM_OPS(bcma_pm_ops, bcma_host_pci_suspend,
static DEFINE_PCI_DEVICE_TABLE(bcma_pci_bridge_tbl) = {
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x0576) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 43224) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4331) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4353) },
{ PCI_DEVICE(PCI_VENDOR_ID_BROADCOM, 0x4357) },
......
......@@ -118,8 +118,9 @@ static int bcma_register_cores(struct bcma_bus *bus)
err = device_register(&core->dev);
if (err) {
pr_err("Could not register dev for core 0x%03X\n",
core->id.id);
bcma_err(bus,
"Could not register dev for core 0x%03X\n",
core->id.id);
continue;
}
core->dev_registered = true;
......@@ -151,7 +152,7 @@ int __devinit bcma_bus_register(struct bcma_bus *bus)
/* Scan for devices (cores) */
err = bcma_bus_scan(bus);
if (err) {
pr_err("Failed to scan: %d\n", err);
bcma_err(bus, "Failed to scan: %d\n", err);
return -1;
}
......@@ -179,14 +180,14 @@ int __devinit bcma_bus_register(struct bcma_bus *bus)
/* Try to get SPROM */
err = bcma_sprom_get(bus);
if (err == -ENOENT) {
pr_err("No SPROM available\n");
bcma_err(bus, "No SPROM available\n");
} else if (err)
pr_err("Failed to get SPROM: %d\n", err);
bcma_err(bus, "Failed to get SPROM: %d\n", err);
/* Register found cores */
bcma_register_cores(bus);
pr_info("Bus registered\n");
bcma_info(bus, "Bus registered\n");
return 0;
}
......@@ -214,7 +215,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
/* Scan for chip common core */
err = bcma_bus_scan_early(bus, &match, core_cc);
if (err) {
pr_err("Failed to scan for common core: %d\n", err);
bcma_err(bus, "Failed to scan for common core: %d\n", err);
return -1;
}
......@@ -226,7 +227,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
/* Scan for mips core */
err = bcma_bus_scan_early(bus, &match, core_mips);
if (err) {
pr_err("Failed to scan for mips core: %d\n", err);
bcma_err(bus, "Failed to scan for mips core: %d\n", err);
return -1;
}
......@@ -244,7 +245,7 @@ int __init bcma_bus_early_register(struct bcma_bus *bus,
bcma_core_mips_init(&bus->drv_mips);
}
pr_info("Early bus registered\n");
bcma_info(bus, "Early bus registered\n");
return 0;
}
......
......@@ -340,7 +340,7 @@ static int bcma_get_next_core(struct bcma_bus *bus, u32 __iomem **eromptr,
if (tmp <= 0) {
return -EILSEQ;
} else {
pr_info("Bridge found\n");
bcma_info(bus, "Bridge found\n");
return -ENXIO;
}
}
......@@ -427,8 +427,8 @@ void bcma_init_bus(struct bcma_bus *bus)
chipinfo->id = (tmp & BCMA_CC_ID_ID) >> BCMA_CC_ID_ID_SHIFT;
chipinfo->rev = (tmp & BCMA_CC_ID_REV) >> BCMA_CC_ID_REV_SHIFT;
chipinfo->pkg = (tmp & BCMA_CC_ID_PKG) >> BCMA_CC_ID_PKG_SHIFT;
pr_info("Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
chipinfo->id, chipinfo->rev, chipinfo->pkg);
bcma_info(bus, "Found chip with id 0x%04X, rev 0x%02X and package 0x%02X\n",
chipinfo->id, chipinfo->rev, chipinfo->pkg);
bus->init_done = true;
}
......@@ -482,11 +482,10 @@ int bcma_bus_scan(struct bcma_bus *bus)
other_core = bcma_find_core_reverse(bus, core->id.id);
core->core_unit = (other_core == NULL) ? 0 : other_core->core_unit + 1;
pr_info("Core %d found: %s "
"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
core->core_index, bcma_device_name(&core->id),
core->id.manuf, core->id.id, core->id.rev,
core->id.class);
bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
core->core_index, bcma_device_name(&core->id),
core->id.manuf, core->id.id, core->id.rev,
core->id.class);
list_add(&core->list, &bus->cores);
}
......@@ -538,11 +537,10 @@ int __init bcma_bus_scan_early(struct bcma_bus *bus,
core->core_index = core_num++;
bus->nr_cores++;
pr_info("Core %d found: %s "
"(manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
core->core_index, bcma_device_name(&core->id),
core->id.manuf, core->id.id, core->id.rev,
core->id.class);
bcma_info(bus, "Core %d found: %s (manuf 0x%03X, id 0x%03X, rev 0x%02X, class 0x%X)\n",
core->core_index, bcma_device_name(&core->id),
core->id.manuf, core->id.id, core->id.rev,
core->id.class);
list_add(&core->list, &bus->cores);
err = 0;
......
......@@ -60,11 +60,11 @@ static int bcma_fill_sprom_with_fallback(struct bcma_bus *bus,
if (err)
goto fail;
pr_debug("Using SPROM revision %d provided by"
" platform.\n", bus->sprom.revision);
bcma_debug(bus, "Using SPROM revision %d provided by platform.\n",
bus->sprom.revision);
return 0;
fail:
pr_warn("Using fallback SPROM failed (err %d)\n", err);
bcma_warn(bus, "Using fallback SPROM failed (err %d)\n", err);
return err;
}
......@@ -468,11 +468,11 @@ static bool bcma_sprom_ext_available(struct bcma_bus *bus)
/* older chipcommon revisions use chip status register */
chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
switch (bus->chipinfo.id) {
case 0x4313:
case BCMA_CHIP_ID_BCM4313:
present_mask = BCMA_CC_CHIPST_4313_SPROM_PRESENT;
break;
case 0x4331:
case BCMA_CHIP_ID_BCM4331:
present_mask = BCMA_CC_CHIPST_4331_SPROM_PRESENT;
break;
......@@ -494,16 +494,16 @@ static bool bcma_sprom_onchip_available(struct bcma_bus *bus)
chip_status = bcma_read32(bus->drv_cc.core, BCMA_CC_CHIPSTAT);
switch (bus->chipinfo.id) {
case 0x4313:
case BCMA_CHIP_ID_BCM4313:
present = chip_status & BCMA_CC_CHIPST_4313_OTP_PRESENT;
break;
case 0x4331:
case BCMA_CHIP_ID_BCM4331:
present = chip_status & BCMA_CC_CHIPST_4331_OTP_PRESENT;
break;
case 43224:
case 43225:
case BCMA_CHIP_ID_BCM43224:
case BCMA_CHIP_ID_BCM43225:
/* for these chips OTP is always available */
present = true;
break;
......@@ -579,13 +579,15 @@ int bcma_sprom_get(struct bcma_bus *bus)
if (!sprom)
return -ENOMEM;
if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431)
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, false);
pr_debug("SPROM offset 0x%x\n", offset);
bcma_debug(bus, "SPROM offset 0x%x\n", offset);
bcma_sprom_read(bus, offset, sprom);
if (bus->chipinfo.id == 0x4331 || bus->chipinfo.id == 43431)
if (bus->chipinfo.id == BCMA_CHIP_ID_BCM4331 ||
bus->chipinfo.id == BCMA_CHIP_ID_BCM43431)
bcma_chipco_bcm4331_ext_pa_lines_ctl(&bus->drv_cc, true);
err = bcma_sprom_valid(sprom);
......
......@@ -511,7 +511,6 @@ config USB_SWITCH_FSA9480
source "drivers/misc/c2port/Kconfig"
source "drivers/misc/eeprom/Kconfig"
source "drivers/misc/cb710/Kconfig"
source "drivers/misc/iwmc3200top/Kconfig"
source "drivers/misc/ti-st/Kconfig"
source "drivers/misc/lis3lv02d/Kconfig"
source "drivers/misc/carma/Kconfig"
......
......@@ -36,7 +36,6 @@ obj-$(CONFIG_EP93XX_PWM) += ep93xx_pwm.o
obj-$(CONFIG_DS1682) += ds1682.o
obj-$(CONFIG_TI_DAC7512) += ti_dac7512.o
obj-$(CONFIG_C2PORT) += c2port/
obj-$(CONFIG_IWMC3200TOP) += iwmc3200top/
obj-$(CONFIG_HMC6352) += hmc6352.o
obj-y += eeprom/
obj-y += cb710/
......
config IWMC3200TOP
tristate "Intel Wireless MultiCom Top Driver"
depends on MMC && EXPERIMENTAL
select FW_LOADER
---help---
Intel Wireless MultiCom 3200 Top driver is responsible for
for firmware load and enabled coms enumeration
config IWMC3200TOP_DEBUG
bool "Enable full debug output of iwmc3200top Driver"
depends on IWMC3200TOP
---help---
Enable full debug output of iwmc3200top Driver
config IWMC3200TOP_DEBUGFS
bool "Enable Debugfs debugging interface for iwmc3200top"
depends on IWMC3200TOP
---help---
Enable creation of debugfs files for iwmc3200top
# iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
# drivers/misc/iwmc3200top/Makefile
#
# Copyright (C) 2009 Intel Corporation. All rights reserved.
#
# This program is free software; you can redistribute it and/or
# modify it under the terms of the GNU General Public License version
# 2 as published by the Free Software Foundation.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
# 02110-1301, USA.
#
#
# Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
# -
#
#
obj-$(CONFIG_IWMC3200TOP) += iwmc3200top.o
iwmc3200top-objs := main.o fw-download.o
iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUG) += log.o
iwmc3200top-$(CONFIG_IWMC3200TOP_DEBUGFS) += debugfs.o
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/debufs.c
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#include <linux/kernel.h>
#include <linux/slab.h>
#include <linux/string.h>
#include <linux/ctype.h>
#include <linux/mmc/sdio_func.h>
#include <linux/mmc/sdio.h>
#include <linux/debugfs.h>
#include "iwmc3200top.h"
#include "fw-msg.h"
#include "log.h"
#include "debugfs.h"
/* Constants definition */
#define HEXADECIMAL_RADIX 16
/* Functions definition */
#define DEBUGFS_ADD(name, parent) do { \
dbgfs->dbgfs_##parent##_files.file_##name = \
debugfs_create_file(#name, 0644, dbgfs->dir_##parent, priv, \
&iwmct_dbgfs_##name##_ops); \
} while (0)
#define DEBUGFS_RM(name) do { \
debugfs_remove(name); \
name = NULL; \
} while (0)
#define DEBUGFS_READ_FUNC(name) \
ssize_t iwmct_dbgfs_##name##_read(struct file *file, \
char __user *user_buf, \
size_t count, loff_t *ppos);
#define DEBUGFS_WRITE_FUNC(name) \
ssize_t iwmct_dbgfs_##name##_write(struct file *file, \
const char __user *user_buf, \
size_t count, loff_t *ppos);
#define DEBUGFS_READ_FILE_OPS(name) \
DEBUGFS_READ_FUNC(name) \
static const struct file_operations iwmct_dbgfs_##name##_ops = { \
.read = iwmct_dbgfs_##name##_read, \
.open = iwmct_dbgfs_open_file_generic, \
.llseek = generic_file_llseek, \
};
#define DEBUGFS_WRITE_FILE_OPS(name) \
DEBUGFS_WRITE_FUNC(name) \
static const struct file_operations iwmct_dbgfs_##name##_ops = { \
.write = iwmct_dbgfs_##name##_write, \
.open = iwmct_dbgfs_open_file_generic, \
.llseek = generic_file_llseek, \
};
#define DEBUGFS_READ_WRITE_FILE_OPS(name) \
DEBUGFS_READ_FUNC(name) \
DEBUGFS_WRITE_FUNC(name) \
static const struct file_operations iwmct_dbgfs_##name##_ops = {\
.write = iwmct_dbgfs_##name##_write, \
.read = iwmct_dbgfs_##name##_read, \
.open = iwmct_dbgfs_open_file_generic, \
.llseek = generic_file_llseek, \
};
/* Debugfs file ops definitions */
/*
* Create the debugfs files and directories
*
*/
void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
{
struct iwmct_debugfs *dbgfs;
dbgfs = kzalloc(sizeof(struct iwmct_debugfs), GFP_KERNEL);
if (!dbgfs) {
LOG_ERROR(priv, DEBUGFS, "failed to allocate %zd bytes\n",
sizeof(struct iwmct_debugfs));
return;
}
priv->dbgfs = dbgfs;
dbgfs->name = name;
dbgfs->dir_drv = debugfs_create_dir(name, NULL);
if (!dbgfs->dir_drv) {
LOG_ERROR(priv, DEBUGFS, "failed to create debugfs dir\n");
return;
}
return;
}
/**
* Remove the debugfs files and directories
*
*/
void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
{
if (!dbgfs)
return;
DEBUGFS_RM(dbgfs->dir_drv);
kfree(dbgfs);
dbgfs = NULL;
}
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/debufs.h
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#ifndef __DEBUGFS_H__
#define __DEBUGFS_H__
#ifdef CONFIG_IWMC3200TOP_DEBUGFS
struct iwmct_debugfs {
const char *name;
struct dentry *dir_drv;
struct dir_drv_files {
} dbgfs_drv_files;
};
void iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name);
void iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs);
#else /* CONFIG_IWMC3200TOP_DEBUGFS */
struct iwmct_debugfs;
static inline void
iwmct_dbgfs_register(struct iwmct_priv *priv, const char *name)
{}
static inline void
iwmct_dbgfs_unregister(struct iwmct_debugfs *dbgfs)
{}
#endif /* CONFIG_IWMC3200TOP_DEBUGFS */
#endif /* __DEBUGFS_H__ */
This diff is collapsed.
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/fw-msg.h
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#ifndef __FWMSG_H__
#define __FWMSG_H__
#define COMM_TYPE_D2H 0xFF
#define COMM_TYPE_H2D 0xEE
#define COMM_CATEGORY_OPERATIONAL 0x00
#define COMM_CATEGORY_DEBUG 0x01
#define COMM_CATEGORY_TESTABILITY 0x02
#define COMM_CATEGORY_DIAGNOSTICS 0x03
#define OP_DBG_ZSTR_MSG cpu_to_le16(0x1A)
#define FW_LOG_SRC_MAX 32
#define FW_LOG_SRC_ALL 255
#define FW_STRING_TABLE_ADDR cpu_to_le32(0x0C000000)
#define CMD_DBG_LOG_LEVEL cpu_to_le16(0x0001)
#define CMD_TST_DEV_RESET cpu_to_le16(0x0060)
#define CMD_TST_FUNC_RESET cpu_to_le16(0x0062)
#define CMD_TST_IFACE_RESET cpu_to_le16(0x0064)
#define CMD_TST_CPU_UTILIZATION cpu_to_le16(0x0065)
#define CMD_TST_TOP_DEEP_SLEEP cpu_to_le16(0x0080)
#define CMD_TST_WAKEUP cpu_to_le16(0x0081)
#define CMD_TST_FUNC_WAKEUP cpu_to_le16(0x0082)
#define CMD_TST_FUNC_DEEP_SLEEP_REQUEST cpu_to_le16(0x0083)
#define CMD_TST_GET_MEM_DUMP cpu_to_le16(0x0096)
#define OP_OPR_ALIVE cpu_to_le16(0x0010)
#define OP_OPR_CMD_ACK cpu_to_le16(0x001F)
#define OP_OPR_CMD_NACK cpu_to_le16(0x0020)
#define OP_TST_MEM_DUMP cpu_to_le16(0x0043)
#define CMD_FLAG_PADDING_256 0x80
#define FW_HCMD_BLOCK_SIZE 256
struct msg_hdr {
u8 type;
u8 category;
__le16 opcode;
u8 seqnum;
u8 flags;
__le16 length;
} __attribute__((__packed__));
struct log_hdr {
__le32 timestamp;
u8 severity;
u8 logsource;
__le16 reserved;
} __attribute__((__packed__));
struct mdump_hdr {
u8 dmpid;
u8 frag;
__le16 size;
__le32 addr;
} __attribute__((__packed__));
struct top_msg {
struct msg_hdr hdr;
union {
/* D2H messages */
struct {
struct log_hdr log_hdr;
u8 data[1];
} __attribute__((__packed__)) log;
struct {
struct log_hdr log_hdr;
struct mdump_hdr md_hdr;
u8 data[1];
} __attribute__((__packed__)) mdump;
/* H2D messages */
struct {
u8 logsource;
u8 sevmask;
} __attribute__((__packed__)) logdefs[FW_LOG_SRC_MAX];
struct mdump_hdr mdump_req;
} u;
} __attribute__((__packed__));
#endif /* __FWMSG_H__ */
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/iwmc3200top.h
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#ifndef __IWMC3200TOP_H__
#define __IWMC3200TOP_H__
#include <linux/workqueue.h>
#define DRV_NAME "iwmc3200top"
#define FW_API_VER 1
#define _FW_NAME(api) DRV_NAME "." #api ".fw"
#define FW_NAME(api) _FW_NAME(api)
#define IWMC_SDIO_BLK_SIZE 256
#define IWMC_DEFAULT_TR_BLK 64
#define IWMC_SDIO_DATA_ADDR 0x0
#define IWMC_SDIO_INTR_ENABLE_ADDR 0x14
#define IWMC_SDIO_INTR_STATUS_ADDR 0x13
#define IWMC_SDIO_INTR_CLEAR_ADDR 0x13
#define IWMC_SDIO_INTR_GET_SIZE_ADDR 0x2C
#define COMM_HUB_HEADER_LENGTH 16
#define LOGGER_HEADER_LENGTH 10
#define BARKER_DNLOAD_BT_POS 0
#define BARKER_DNLOAD_BT_MSK BIT(BARKER_DNLOAD_BT_POS)
#define BARKER_DNLOAD_GPS_POS 1
#define BARKER_DNLOAD_GPS_MSK BIT(BARKER_DNLOAD_GPS_POS)
#define BARKER_DNLOAD_TOP_POS 2
#define BARKER_DNLOAD_TOP_MSK BIT(BARKER_DNLOAD_TOP_POS)
#define BARKER_DNLOAD_RESERVED1_POS 3
#define BARKER_DNLOAD_RESERVED1_MSK BIT(BARKER_DNLOAD_RESERVED1_POS)
#define BARKER_DNLOAD_JUMP_POS 4
#define BARKER_DNLOAD_JUMP_MSK BIT(BARKER_DNLOAD_JUMP_POS)
#define BARKER_DNLOAD_SYNC_POS 5
#define BARKER_DNLOAD_SYNC_MSK BIT(BARKER_DNLOAD_SYNC_POS)
#define BARKER_DNLOAD_RESERVED2_POS 6
#define BARKER_DNLOAD_RESERVED2_MSK (0x3 << BARKER_DNLOAD_RESERVED2_POS)
#define BARKER_DNLOAD_BARKER_POS 8
#define BARKER_DNLOAD_BARKER_MSK (0xffffff << BARKER_DNLOAD_BARKER_POS)
#define IWMC_BARKER_REBOOT (0xdeadbe << BARKER_DNLOAD_BARKER_POS)
/* whole field barker */
#define IWMC_BARKER_ACK 0xfeedbabe
#define IWMC_CMD_SIGNATURE 0xcbbc
#define CMD_HDR_OPCODE_POS 0
#define CMD_HDR_OPCODE_MSK_MSK (0xf << CMD_HDR_OPCODE_MSK_POS)
#define CMD_HDR_RESPONSE_CODE_POS 4
#define CMD_HDR_RESPONSE_CODE_MSK (0xf << CMD_HDR_RESPONSE_CODE_POS)
#define CMD_HDR_USE_CHECKSUM_POS 8
#define CMD_HDR_USE_CHECKSUM_MSK BIT(CMD_HDR_USE_CHECKSUM_POS)
#define CMD_HDR_RESPONSE_REQUIRED_POS 9
#define CMD_HDR_RESPONSE_REQUIRED_MSK BIT(CMD_HDR_RESPONSE_REQUIRED_POS)
#define CMD_HDR_DIRECT_ACCESS_POS 10
#define CMD_HDR_DIRECT_ACCESS_MSK BIT(CMD_HDR_DIRECT_ACCESS_POS)
#define CMD_HDR_RESERVED_POS 11
#define CMD_HDR_RESERVED_MSK BIT(0x1f << CMD_HDR_RESERVED_POS)
#define CMD_HDR_SIGNATURE_POS 16
#define CMD_HDR_SIGNATURE_MSK BIT(0xffff << CMD_HDR_SIGNATURE_POS)
enum {
IWMC_OPCODE_PING = 0,
IWMC_OPCODE_READ = 1,
IWMC_OPCODE_WRITE = 2,
IWMC_OPCODE_JUMP = 3,
IWMC_OPCODE_REBOOT = 4,
IWMC_OPCODE_PERSISTENT_WRITE = 5,
IWMC_OPCODE_PERSISTENT_READ = 6,
IWMC_OPCODE_READ_MODIFY_WRITE = 7,
IWMC_OPCODE_LAST_COMMAND = 15
};
struct iwmct_fw_load_hdr {
__le32 cmd;
__le32 target_addr;
__le32 data_size;
__le32 block_chksm;
u8 data[0];
};
/**
* struct iwmct_fw_hdr
* holds all sw components versions
*/
struct iwmct_fw_hdr {
u8 top_major;
u8 top_minor;
u8 top_revision;
u8 gps_major;
u8 gps_minor;
u8 gps_revision;
u8 bt_major;
u8 bt_minor;
u8 bt_revision;
u8 tic_name[31];
};
/**
* struct iwmct_fw_sec_hdr
* @type: function type
* @data_size: section's data size
* @target_addr: download address
*/
struct iwmct_fw_sec_hdr {
u8 type[4];
__le32 data_size;
__le32 target_addr;
};
/**
* struct iwmct_parser
* @file: fw image
* @file_size: fw size
* @cur_pos: position in file
* @buf: temp buf for download
* @buf_size: size of buf
* @entry_point: address to jump in fw kick-off
*/
struct iwmct_parser {
const u8 *file;
size_t file_size;
size_t cur_pos;
u8 *buf;
size_t buf_size;
u32 entry_point;
struct iwmct_fw_hdr versions;
};
struct iwmct_work_struct {
struct list_head list;
ssize_t iosize;
};
struct iwmct_dbg {
int blocks;
bool dump;
bool jump;
bool direct;
bool checksum;
bool fw_download;
int block_size;
int download_trans_blks;
char label_fw[256];
};
struct iwmct_debugfs;
struct iwmct_priv {
struct sdio_func *func;
struct iwmct_debugfs *dbgfs;
struct iwmct_parser parser;
atomic_t reset;
atomic_t dev_sync;
u32 trans_len;
u32 barker;
struct iwmct_dbg dbg;
/* drivers work items */
struct work_struct bus_rescan_worker;
struct work_struct isr_worker;
/* drivers wait queue */
wait_queue_head_t wait_q;
/* rx request list */
struct list_head read_req_list;
};
extern int iwmct_tx(struct iwmct_priv *priv, void *src, int count);
extern int iwmct_fw_load(struct iwmct_priv *priv);
extern void iwmct_dbg_init_params(struct iwmct_priv *drv);
extern void iwmct_dbg_init_drv_attrs(struct device_driver *drv);
extern void iwmct_dbg_remove_drv_attrs(struct device_driver *drv);
extern int iwmct_send_hcmd(struct iwmct_priv *priv, u8 *cmd, u16 len);
#endif /* __IWMC3200TOP_H__ */
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/log.c
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#include <linux/kernel.h>
#include <linux/mmc/sdio_func.h>
#include <linux/slab.h>
#include <linux/ctype.h>
#include "fw-msg.h"
#include "iwmc3200top.h"
#include "log.h"
/* Maximal hexadecimal string size of the FW memdump message */
#define LOG_MSG_SIZE_MAX 12400
/* iwmct_logdefs is a global used by log macros */
u8 iwmct_logdefs[LOG_SRC_MAX];
static u8 iwmct_fw_logdefs[FW_LOG_SRC_MAX];
static int _log_set_log_filter(u8 *logdefs, int size, u8 src, u8 logmask)
{
int i;
if (src < size)
logdefs[src] = logmask;
else if (src == LOG_SRC_ALL)
for (i = 0; i < size; i++)
logdefs[i] = logmask;
else
return -1;
return 0;
}
int iwmct_log_set_filter(u8 src, u8 logmask)
{
return _log_set_log_filter(iwmct_logdefs, LOG_SRC_MAX, src, logmask);
}
int iwmct_log_set_fw_filter(u8 src, u8 logmask)
{
return _log_set_log_filter(iwmct_fw_logdefs,
FW_LOG_SRC_MAX, src, logmask);
}
static int log_msg_format_hex(char *str, int slen, u8 *ibuf,
int ilen, char *pref)
{
int pos = 0;
int i;
int len;
for (pos = 0, i = 0; pos < slen - 2 && pref[i] != '\0'; i++, pos++)
str[pos] = pref[i];
for (i = 0; pos < slen - 2 && i < ilen; pos += len, i++)
len = snprintf(&str[pos], slen - pos - 1, " %2.2X", ibuf[i]);
if (i < ilen)
return -1;
return 0;
}
/* NOTE: This function is not thread safe.
Currently it's called only from sdio rx worker - no race there
*/
void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len)
{
struct top_msg *msg;
static char logbuf[LOG_MSG_SIZE_MAX];
msg = (struct top_msg *)buf;
if (len < sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr)) {
LOG_ERROR(priv, FW_MSG, "Log message from TOP "
"is too short %d (expected %zd)\n",
len, sizeof(msg->hdr) + sizeof(msg->u.log.log_hdr));
return;
}
if (!(iwmct_fw_logdefs[msg->u.log.log_hdr.logsource] &
BIT(msg->u.log.log_hdr.severity)) ||
!(iwmct_logdefs[LOG_SRC_FW_MSG] & BIT(msg->u.log.log_hdr.severity)))
return;
switch (msg->hdr.category) {
case COMM_CATEGORY_TESTABILITY:
if (!(iwmct_logdefs[LOG_SRC_TST] &
BIT(msg->u.log.log_hdr.severity)))
return;
if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
le16_to_cpu(msg->hdr.length) +
sizeof(msg->hdr), "<TST>"))
LOG_WARNING(priv, TST,
"TOP TST message is too long, truncating...");
LOG_WARNING(priv, TST, "%s\n", logbuf);
break;
case COMM_CATEGORY_DEBUG:
if (msg->hdr.opcode == OP_DBG_ZSTR_MSG)
LOG_INFO(priv, FW_MSG, "%s %s", "<DBG>",
((u8 *)msg) + sizeof(msg->hdr)
+ sizeof(msg->u.log.log_hdr));
else {
if (log_msg_format_hex(logbuf, LOG_MSG_SIZE_MAX, buf,
le16_to_cpu(msg->hdr.length)
+ sizeof(msg->hdr),
"<DBG>"))
LOG_WARNING(priv, FW_MSG,
"TOP DBG message is too long,"
"truncating...");
LOG_WARNING(priv, FW_MSG, "%s\n", logbuf);
}
break;
default:
break;
}
}
static int _log_get_filter_str(u8 *logdefs, int logdefsz, char *buf, int size)
{
int i, pos, len;
for (i = 0, pos = 0; (pos < size-1) && (i < logdefsz); i++) {
len = snprintf(&buf[pos], size - pos - 1, "0x%02X%02X,",
i, logdefs[i]);
pos += len;
}
buf[pos-1] = '\n';
buf[pos] = '\0';
if (i < logdefsz)
return -1;
return 0;
}
int log_get_filter_str(char *buf, int size)
{
return _log_get_filter_str(iwmct_logdefs, LOG_SRC_MAX, buf, size);
}
int log_get_fw_filter_str(char *buf, int size)
{
return _log_get_filter_str(iwmct_fw_logdefs, FW_LOG_SRC_MAX, buf, size);
}
#define HEXADECIMAL_RADIX 16
#define LOG_SRC_FORMAT 7 /* log level is in format of "0xXXXX," */
ssize_t show_iwmct_log_level(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwmct_priv *priv = dev_get_drvdata(d);
char *str_buf;
int buf_size;
ssize_t ret;
buf_size = (LOG_SRC_FORMAT * LOG_SRC_MAX) + 1;
str_buf = kzalloc(buf_size, GFP_KERNEL);
if (!str_buf) {
LOG_ERROR(priv, DEBUGFS,
"failed to allocate %d bytes\n", buf_size);
ret = -ENOMEM;
goto exit;
}
if (log_get_filter_str(str_buf, buf_size) < 0) {
ret = -EINVAL;
goto exit;
}
ret = sprintf(buf, "%s", str_buf);
exit:
kfree(str_buf);
return ret;
}
ssize_t store_iwmct_log_level(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct iwmct_priv *priv = dev_get_drvdata(d);
char *token, *str_buf = NULL;
long val;
ssize_t ret = count;
u8 src, mask;
if (!count)
goto exit;
str_buf = kzalloc(count, GFP_KERNEL);
if (!str_buf) {
LOG_ERROR(priv, DEBUGFS,
"failed to allocate %zd bytes\n", count);
ret = -ENOMEM;
goto exit;
}
memcpy(str_buf, buf, count);
while ((token = strsep(&str_buf, ",")) != NULL) {
while (isspace(*token))
++token;
if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
LOG_ERROR(priv, DEBUGFS,
"failed to convert string to long %s\n",
token);
ret = -EINVAL;
goto exit;
}
mask = val & 0xFF;
src = (val & 0XFF00) >> 8;
iwmct_log_set_filter(src, mask);
}
exit:
kfree(str_buf);
return ret;
}
ssize_t show_iwmct_log_level_fw(struct device *d,
struct device_attribute *attr, char *buf)
{
struct iwmct_priv *priv = dev_get_drvdata(d);
char *str_buf;
int buf_size;
ssize_t ret;
buf_size = (LOG_SRC_FORMAT * FW_LOG_SRC_MAX) + 2;
str_buf = kzalloc(buf_size, GFP_KERNEL);
if (!str_buf) {
LOG_ERROR(priv, DEBUGFS,
"failed to allocate %d bytes\n", buf_size);
ret = -ENOMEM;
goto exit;
}
if (log_get_fw_filter_str(str_buf, buf_size) < 0) {
ret = -EINVAL;
goto exit;
}
ret = sprintf(buf, "%s", str_buf);
exit:
kfree(str_buf);
return ret;
}
ssize_t store_iwmct_log_level_fw(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct iwmct_priv *priv = dev_get_drvdata(d);
struct top_msg cmd;
char *token, *str_buf = NULL;
ssize_t ret = count;
u16 cmdlen = 0;
int i;
long val;
u8 src, mask;
if (!count)
goto exit;
str_buf = kzalloc(count, GFP_KERNEL);
if (!str_buf) {
LOG_ERROR(priv, DEBUGFS,
"failed to allocate %zd bytes\n", count);
ret = -ENOMEM;
goto exit;
}
memcpy(str_buf, buf, count);
cmd.hdr.type = COMM_TYPE_H2D;
cmd.hdr.category = COMM_CATEGORY_DEBUG;
cmd.hdr.opcode = CMD_DBG_LOG_LEVEL;
for (i = 0; ((token = strsep(&str_buf, ",")) != NULL) &&
(i < FW_LOG_SRC_MAX); i++) {
while (isspace(*token))
++token;
if (strict_strtol(token, HEXADECIMAL_RADIX, &val)) {
LOG_ERROR(priv, DEBUGFS,
"failed to convert string to long %s\n",
token);
ret = -EINVAL;
goto exit;
}
mask = val & 0xFF; /* LSB */
src = (val & 0XFF00) >> 8; /* 2nd least significant byte. */
iwmct_log_set_fw_filter(src, mask);
cmd.u.logdefs[i].logsource = src;
cmd.u.logdefs[i].sevmask = mask;
}
cmd.hdr.length = cpu_to_le16(i * sizeof(cmd.u.logdefs[0]));
cmdlen = (i * sizeof(cmd.u.logdefs[0]) + sizeof(cmd.hdr));
ret = iwmct_send_hcmd(priv, (u8 *)&cmd, cmdlen);
if (ret) {
LOG_ERROR(priv, DEBUGFS,
"Failed to send %d bytes of fwcmd, ret=%zd\n",
cmdlen, ret);
goto exit;
} else
LOG_INFO(priv, DEBUGFS, "fwcmd sent (%d bytes)\n", cmdlen);
ret = count;
exit:
kfree(str_buf);
return ret;
}
/*
* iwmc3200top - Intel Wireless MultiCom 3200 Top Driver
* drivers/misc/iwmc3200top/log.h
*
* Copyright (C) 2009 Intel Corporation. All rights reserved.
*
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License version
* 2 as published by the Free Software Foundation.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
* 02110-1301, USA.
*
*
* Author Name: Maxim Grabarnik <maxim.grabarnink@intel.com>
* -
*
*/
#ifndef __LOG_H__
#define __LOG_H__
/* log severity:
* The log levels here match FW log levels
* so values need to stay as is */
#define LOG_SEV_CRITICAL 0
#define LOG_SEV_ERROR 1
#define LOG_SEV_WARNING 2
#define LOG_SEV_INFO 3
#define LOG_SEV_INFOEX 4
/* Log levels not defined for FW */
#define LOG_SEV_TRACE 5
#define LOG_SEV_DUMP 6
#define LOG_SEV_FW_FILTER_ALL \
(BIT(LOG_SEV_CRITICAL) | \
BIT(LOG_SEV_ERROR) | \
BIT(LOG_SEV_WARNING) | \
BIT(LOG_SEV_INFO) | \
BIT(LOG_SEV_INFOEX))
#define LOG_SEV_FILTER_ALL \
(BIT(LOG_SEV_CRITICAL) | \
BIT(LOG_SEV_ERROR) | \
BIT(LOG_SEV_WARNING) | \
BIT(LOG_SEV_INFO) | \
BIT(LOG_SEV_INFOEX) | \
BIT(LOG_SEV_TRACE) | \
BIT(LOG_SEV_DUMP))
/* log source */
#define LOG_SRC_INIT 0
#define LOG_SRC_DEBUGFS 1
#define LOG_SRC_FW_DOWNLOAD 2
#define LOG_SRC_FW_MSG 3
#define LOG_SRC_TST 4
#define LOG_SRC_IRQ 5
#define LOG_SRC_MAX 6
#define LOG_SRC_ALL 0xFF
/**
* Default intitialization runtime log level
*/
#ifndef LOG_SEV_FILTER_RUNTIME
#define LOG_SEV_FILTER_RUNTIME \
(BIT(LOG_SEV_CRITICAL) | \
BIT(LOG_SEV_ERROR) | \
BIT(LOG_SEV_WARNING))
#endif
#ifndef FW_LOG_SEV_FILTER_RUNTIME
#define FW_LOG_SEV_FILTER_RUNTIME LOG_SEV_FILTER_ALL
#endif
#ifdef CONFIG_IWMC3200TOP_DEBUG
/**
* Log macros
*/
#define priv2dev(priv) (&(priv->func)->dev)
#define LOG_CRITICAL(priv, src, fmt, args...) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_CRITICAL)) \
dev_crit(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_ERROR(priv, src, fmt, args...) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_ERROR)) \
dev_err(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_WARNING(priv, src, fmt, args...) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_WARNING)) \
dev_warn(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_INFO(priv, src, fmt, args...) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_INFO)) \
dev_info(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_TRACE(priv, src, fmt, args...) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_TRACE)) \
dev_dbg(priv2dev(priv), "%s %d: " fmt, \
__func__, __LINE__, ##args); \
} while (0)
#define LOG_HEXDUMP(src, ptr, len) \
do { \
if (iwmct_logdefs[LOG_SRC_ ## src] & BIT(LOG_SEV_DUMP)) \
print_hex_dump(KERN_DEBUG, "", DUMP_PREFIX_NONE, \
16, 1, ptr, len, false); \
} while (0)
void iwmct_log_top_message(struct iwmct_priv *priv, u8 *buf, int len);
extern u8 iwmct_logdefs[];
int iwmct_log_set_filter(u8 src, u8 logmask);
int iwmct_log_set_fw_filter(u8 src, u8 logmask);
ssize_t show_iwmct_log_level(struct device *d,
struct device_attribute *attr, char *buf);
ssize_t store_iwmct_log_level(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count);
ssize_t show_iwmct_log_level_fw(struct device *d,
struct device_attribute *attr, char *buf);
ssize_t store_iwmct_log_level_fw(struct device *d,
struct device_attribute *attr,
const char *buf, size_t count);
#else
#define LOG_CRITICAL(priv, src, fmt, args...)
#define LOG_ERROR(priv, src, fmt, args...)
#define LOG_WARNING(priv, src, fmt, args...)
#define LOG_INFO(priv, src, fmt, args...)
#define LOG_TRACE(priv, src, fmt, args...)
#define LOG_HEXDUMP(src, ptr, len)
static inline void iwmct_log_top_message(struct iwmct_priv *priv,
u8 *buf, int len) {}
static inline int iwmct_log_set_filter(u8 src, u8 logmask) { return 0; }
static inline int iwmct_log_set_fw_filter(u8 src, u8 logmask) { return 0; }
#endif /* CONFIG_IWMC3200TOP_DEBUG */
int log_get_filter_str(char *buf, int size);
int log_get_fw_filter_str(char *buf, int size);
#endif /* __LOG_H__ */
This diff is collapsed.
......@@ -7,9 +7,6 @@ config WIMAX_I2400M
comment "Enable USB support to see WiMAX USB drivers"
depends on USB = n
comment "Enable MMC support to see WiMAX SDIO drivers"
depends on MMC = n
config WIMAX_I2400M_USB
tristate "Intel Wireless WiMAX Connection 2400 over USB (including 5x50)"
depends on WIMAX && USB
......@@ -21,25 +18,6 @@ config WIMAX_I2400M_USB
If unsure, it is safe to select M (module).
config WIMAX_I2400M_SDIO
tristate "Intel Wireless WiMAX Connection 2400 over SDIO"
depends on WIMAX && MMC
select WIMAX_I2400M
help
Select if you have a device based on the Intel WiMAX
Connection 2400 over SDIO.
If unsure, it is safe to select M (module).
config WIMAX_IWMC3200_SDIO
bool "Intel Wireless Multicom WiMAX Connection 3200 over SDIO (EXPERIMENTAL)"
depends on WIMAX_I2400M_SDIO
depends on EXPERIMENTAL
select IWMC3200TOP
help
Select if you have a device based on the Intel Multicom WiMAX
Connection 3200 over SDIO.
config WIMAX_I2400M_DEBUG_LEVEL
int "WiMAX i2400m debug level"
depends on WIMAX_I2400M
......
obj-$(CONFIG_WIMAX_I2400M) += i2400m.o
obj-$(CONFIG_WIMAX_I2400M_USB) += i2400m-usb.o
obj-$(CONFIG_WIMAX_I2400M_SDIO) += i2400m-sdio.o
i2400m-y := \
control.o \
......@@ -21,10 +20,3 @@ i2400m-usb-y := \
usb-tx.o \
usb-rx.o \
usb.o
i2400m-sdio-y := \
sdio.o \
sdio-tx.o \
sdio-fw.o \
sdio-rx.o
......@@ -754,8 +754,7 @@ EXPORT_SYMBOL_GPL(i2400m_error_recovery);
/*
* Alloc the command and ack buffers for boot mode
*
* Get the buffers needed to deal with boot mode messages. These
* buffers need to be allocated before the sdio receive irq is setup.
* Get the buffers needed to deal with boot mode messages.
*/
static
int i2400m_bm_buf_alloc(struct i2400m *i2400m)
......
......@@ -51,8 +51,7 @@
* firmware. Normal hardware takes only signed firmware.
*
* On boot mode, in USB, we write to the device using the bulk out
* endpoint and read from it in the notification endpoint. In SDIO we
* talk to it via the write address and read from the read address.
* endpoint and read from it in the notification endpoint.
*
* Upon entrance to boot mode, the device sends (preceded with a few
* zero length packets (ZLPs) on the notification endpoint in USB) a
......
/*
* Intel Wireless WiMAX Connection 2400m
* SDIO-specific i2400m driver definitions
*
*
* Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Intel Corporation <linux-wimax@intel.com>
* Brian Bian <brian.bian@intel.com>
* Dirk Brandewie <dirk.j.brandewie@intel.com>
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
* Yanir Lubetkin <yanirx.lubetkin@intel.com>
* - Initial implementation
*
*
* This driver implements the bus-specific part of the i2400m for
* SDIO. Check i2400m.h for a generic driver description.
*
* ARCHITECTURE
*
* This driver sits under the bus-generic i2400m driver, providing the
* connection to the device.
*
* When probed, all the function pointers are setup and then the
* bus-generic code called. The generic driver will then use the
* provided pointers for uploading firmware (i2400ms_bus_bm*() in
* sdio-fw.c) and then setting up the device (i2400ms_dev_*() in
* sdio.c).
*
* Once firmware is uploaded, TX functions (sdio-tx.c) are called when
* data is ready for transmission in the TX fifo; then the SDIO IRQ is
* fired and data is available (sdio-rx.c), it is sent to the generic
* driver for processing with i2400m_rx.
*/
#ifndef __I2400M_SDIO_H__
#define __I2400M_SDIO_H__
#include "i2400m.h"
/* Host-Device interface for SDIO */
enum {
I2400M_SDIO_BOOT_RETRIES = 3,
I2400MS_BLK_SIZE = 256,
I2400MS_PL_SIZE_MAX = 0x3E00,
I2400MS_DATA_ADDR = 0x0,
I2400MS_INTR_STATUS_ADDR = 0x13,
I2400MS_INTR_CLEAR_ADDR = 0x13,
I2400MS_INTR_ENABLE_ADDR = 0x14,
I2400MS_INTR_GET_SIZE_ADDR = 0x2C,
/* The number of ticks to wait for the device to signal that
* it is ready */
I2400MS_INIT_SLEEP_INTERVAL = 100,
/* How long to wait for the device to settle after reset */
I2400MS_SETTLE_TIME = 40,
/* The number of msec to wait for IOR after sending IOE */
IWMC3200_IOR_TIMEOUT = 10,
};
/**
* struct i2400ms - descriptor for a SDIO connected i2400m
*
* @i2400m: bus-generic i2400m implementation; has to be first (see
* it's documentation in i2400m.h).
*
* @func: pointer to our SDIO function
*
* @tx_worker: workqueue struct used to TX data when the bus-generic
* code signals packets are pending for transmission to the device.
*
* @tx_workqueue: workqeueue used for data TX; we don't use the
* system's workqueue as that might cause deadlocks with code in
* the bus-generic driver. The read/write operation to the queue
* is protected with spinlock (tx_lock in struct i2400m) to avoid
* the queue being destroyed in the middle of a the queue read/write
* operation.
*
* @debugfs_dentry: dentry for the SDIO specific debugfs files
*
* Note this value is set to NULL upon destruction; this is
* because some routinges use it to determine if we are inside the
* probe() path or some other path. When debugfs is disabled,
* creation sets the dentry to '(void*) -ENODEV', which is valid
* for the test.
*/
struct i2400ms {
struct i2400m i2400m; /* FIRST! See doc */
struct sdio_func *func;
struct work_struct tx_worker;
struct workqueue_struct *tx_workqueue;
char tx_wq_name[32];
struct dentry *debugfs_dentry;
wait_queue_head_t bm_wfa_wq;
int bm_wait_result;
size_t bm_ack_size;
/* Device is any of the iwmc3200 SKUs */
unsigned iwmc3200:1;
};
static inline
void i2400ms_init(struct i2400ms *i2400ms)
{
i2400m_init(&i2400ms->i2400m);
}
extern int i2400ms_rx_setup(struct i2400ms *);
extern void i2400ms_rx_release(struct i2400ms *);
extern int i2400ms_tx_setup(struct i2400ms *);
extern void i2400ms_tx_release(struct i2400ms *);
extern void i2400ms_bus_tx_kick(struct i2400m *);
extern ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *,
const struct i2400m_bootrom_header *,
size_t, int);
extern ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *,
struct i2400m_bootrom_header *,
size_t);
extern void i2400ms_bus_bm_release(struct i2400m *);
extern int i2400ms_bus_bm_setup(struct i2400m *);
#endif /* #ifndef __I2400M_SDIO_H__ */
......@@ -46,7 +46,7 @@
* - bus generic driver (this part)
*
* The bus specific driver sets up stuff specific to the bus the
* device is connected to (USB, SDIO, PCI, tam-tam...non-authoritative
* device is connected to (USB, PCI, tam-tam...non-authoritative
* nor binding list) which is basically the device-model management
* (probe/disconnect, etc), moving data from device to kernel and
* back, doing the power saving details and reseting the device.
......@@ -238,14 +238,13 @@ struct i2400m_barker_db;
* amount needed for loading firmware, where us dev_start/stop setup
* the rest needed to do full data/control traffic.
*
* @bus_tx_block_size: [fill] SDIO imposes a 256 block size, USB 16,
* so we have a tx_blk_size variable that the bus layer sets to
* tell the engine how much of that we need.
* @bus_tx_block_size: [fill] USB imposes a 16 block size, but other
* busses will differ. So we have a tx_blk_size variable that the
* bus layer sets to tell the engine how much of that we need.
*
* @bus_tx_room_min: [fill] Minimum room required while allocating
* TX queue's buffer space for message header. SDIO requires
* 224 bytes and USB 16 bytes. Refer bus specific driver code
* for details.
* TX queue's buffer space for message header. USB requires
* 16 bytes. Refer to bus specific driver code for details.
*
* @bus_pl_size_max: [fill] Maximum payload size.
*
......
/*
* debug levels control file for the i2400m module's
*/
#ifndef __debug_levels__h__
#define __debug_levels__h__
/* Maximum compile and run time debug level for all submodules */
#define D_MODULENAME i2400m_sdio
#define D_MASTER CONFIG_WIMAX_I2400M_DEBUG_LEVEL
#include <linux/wimax/debug.h>
/* List of all the enabled modules */
enum d_module {
D_SUBMODULE_DECLARE(main),
D_SUBMODULE_DECLARE(tx),
D_SUBMODULE_DECLARE(rx),
D_SUBMODULE_DECLARE(fw)
};
#endif /* #ifndef __debug_levels__h__ */
/*
* Intel Wireless WiMAX Connection 2400m
* Firmware uploader's SDIO specifics
*
*
* Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Intel Corporation <linux-wimax@intel.com>
* Yanir Lubetkin <yanirx.lubetkin@intel.com>
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
* - Initial implementation
*
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
* - Bus generic/specific split for USB
*
* Dirk Brandewie <dirk.j.brandewie@intel.com>
* - Initial implementation for SDIO
*
* Inaky Perez-Gonzalez <inaky.perez-gonzalez@intel.com>
* - SDIO rehash for changes in the bus-driver model
*
* Dirk Brandewie <dirk.j.brandewie@intel.com>
* - Make it IRQ based, not polling
*
* THE PROCEDURE
*
* See fw.c for the generic description of this procedure.
*
* This file implements only the SDIO specifics. It boils down to how
* to send a command and waiting for an acknowledgement from the
* device.
*
* All this code is sequential -- all i2400ms_bus_bm_*() functions are
* executed in the same thread, except i2400ms_bm_irq() [on its own by
* the SDIO driver]. This makes it possible to avoid locking.
*
* COMMAND EXECUTION
*
* The generic firmware upload code will call i2400m_bus_bm_cmd_send()
* to send commands.
*
* The SDIO devices expects things in 256 byte blocks, so it will pad
* it, compute the checksum (if needed) and pass it to SDIO.
*
* ACK RECEPTION
*
* This works in IRQ mode -- the fw loader says when to wait for data
* and for that it calls i2400ms_bus_bm_wait_for_ack().
*
* This checks if there is any data available (RX size > 0); if not,
* waits for the IRQ handler to notify about it. Once there is data,
* it is read and passed to the caller. Doing it this way we don't
* need much coordination/locking, and it makes it much more difficult
* for an interrupt to be lost and the wait_for_ack() function getting
* stuck even when data is pending.
*/
#include <linux/mmc/sdio_func.h>
#include "i2400m-sdio.h"
#define D_SUBMODULE fw
#include "sdio-debug-levels.h"
/*
* Send a boot-mode command to the SDIO function
*
* We use a bounce buffer (i2400m->bm_cmd_buf) because we need to
* touch the header if the RAW flag is not set.
*
* @flags: pass thru from i2400m_bm_cmd()
* @return: cmd_size if ok, < 0 errno code on error.
*
* Note the command is padded to the SDIO block size for the device.
*/
ssize_t i2400ms_bus_bm_cmd_send(struct i2400m *i2400m,
const struct i2400m_bootrom_header *_cmd,
size_t cmd_size, int flags)
{
ssize_t result;
struct device *dev = i2400m_dev(i2400m);
struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
int opcode = _cmd == NULL ? -1 : i2400m_brh_get_opcode(_cmd);
struct i2400m_bootrom_header *cmd;
/* SDIO restriction */
size_t cmd_size_a = ALIGN(cmd_size, I2400MS_BLK_SIZE);
d_fnstart(5, dev, "(i2400m %p cmd %p size %zu)\n",
i2400m, _cmd, cmd_size);
result = -E2BIG;
if (cmd_size > I2400M_BM_CMD_BUF_SIZE)
goto error_too_big;
if (_cmd != i2400m->bm_cmd_buf)
memmove(i2400m->bm_cmd_buf, _cmd, cmd_size);
cmd = i2400m->bm_cmd_buf;
if (cmd_size_a > cmd_size) /* Zero pad space */
memset(i2400m->bm_cmd_buf + cmd_size, 0, cmd_size_a - cmd_size);
if ((flags & I2400M_BM_CMD_RAW) == 0) {
if (WARN_ON(i2400m_brh_get_response_required(cmd) == 0))
dev_warn(dev, "SW BUG: response_required == 0\n");
i2400m_bm_cmd_prepare(cmd);
}
d_printf(4, dev, "BM cmd %d: %zu bytes (%zu padded)\n",
opcode, cmd_size, cmd_size_a);
d_dump(5, dev, cmd, cmd_size);
sdio_claim_host(i2400ms->func); /* Send & check */
result = sdio_memcpy_toio(i2400ms->func, I2400MS_DATA_ADDR,
i2400m->bm_cmd_buf, cmd_size_a);
sdio_release_host(i2400ms->func);
if (result < 0) {
dev_err(dev, "BM cmd %d: cannot send: %ld\n",
opcode, (long) result);
goto error_cmd_send;
}
result = cmd_size;
error_cmd_send:
error_too_big:
d_fnend(5, dev, "(i2400m %p cmd %p size %zu) = %d\n",
i2400m, _cmd, cmd_size, (int) result);
return result;
}
/*
* Read an ack from the device's boot-mode
*
* @i2400m:
* @_ack: pointer to where to store the read data
* @ack_size: how many bytes we should read
*
* Returns: < 0 errno code on error; otherwise, amount of received bytes.
*
* The ACK for a BM command is always at least sizeof(*ack) bytes, so
* check for that. We don't need to check for device reboots
*
*/
ssize_t i2400ms_bus_bm_wait_for_ack(struct i2400m *i2400m,
struct i2400m_bootrom_header *ack,
size_t ack_size)
{
ssize_t result;
struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
struct sdio_func *func = i2400ms->func;
struct device *dev = &func->dev;
int size;
BUG_ON(sizeof(*ack) > ack_size);
d_fnstart(5, dev, "(i2400m %p ack %p size %zu)\n",
i2400m, ack, ack_size);
result = wait_event_timeout(i2400ms->bm_wfa_wq,
i2400ms->bm_ack_size != -EINPROGRESS,
2 * HZ);
if (result == 0) {
result = -ETIMEDOUT;
dev_err(dev, "BM: error waiting for an ack\n");
goto error_timeout;
}
spin_lock(&i2400m->rx_lock);
result = i2400ms->bm_ack_size;
BUG_ON(result == -EINPROGRESS);
if (result < 0) /* so we exit when rx_release() is called */
dev_err(dev, "BM: %s failed: %zd\n", __func__, result);
else {
size = min(ack_size, i2400ms->bm_ack_size);
memcpy(ack, i2400m->bm_ack_buf, size);
}
/*
* Remember always to clear the bm_ack_size to -EINPROGRESS
* after the RX data is processed
*/
i2400ms->bm_ack_size = -EINPROGRESS;
spin_unlock(&i2400m->rx_lock);
error_timeout:
d_fnend(5, dev, "(i2400m %p ack %p size %zu) = %zd\n",
i2400m, ack, ack_size, result);
return result;
}
/*
* Intel Wireless WiMAX Connection 2400m
* SDIO RX handling
*
*
* Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Intel Corporation <linux-wimax@intel.com>
* Dirk Brandewie <dirk.j.brandewie@intel.com>
* - Initial implementation
*
*
* This handles the RX path on SDIO.
*
* The SDIO bus driver calls the "irq" routine when data is available.
* This is not a traditional interrupt routine since the SDIO bus
* driver calls us from its irq thread context. Because of this
* sleeping in the SDIO RX IRQ routine is okay.
*
* From there on, we obtain the size of the data that is available,
* allocate an skb, copy it and then pass it to the generic driver's
* RX routine [i2400m_rx()].
*
* ROADMAP
*
* i2400ms_irq()
* i2400ms_rx()
* __i2400ms_rx_get_size()
* i2400m_is_boot_barker()
* i2400m_rx()
*
* i2400ms_rx_setup()
*
* i2400ms_rx_release()
*/
#include <linux/workqueue.h>
#include <linux/wait.h>
#include <linux/skbuff.h>
#include <linux/mmc/sdio.h>
#include <linux/mmc/sdio_func.h>
#include <linux/slab.h>
#include "i2400m-sdio.h"
#define D_SUBMODULE rx
#include "sdio-debug-levels.h"
static const __le32 i2400m_ACK_BARKER[4] = {
__constant_cpu_to_le32(I2400M_ACK_BARKER),
__constant_cpu_to_le32(I2400M_ACK_BARKER),
__constant_cpu_to_le32(I2400M_ACK_BARKER),
__constant_cpu_to_le32(I2400M_ACK_BARKER)
};
/*
* Read and return the amount of bytes available for RX
*
* The RX size has to be read like this: byte reads of three
* sequential locations; then glue'em together.
*
* sdio_readl() doesn't work.
*/
static ssize_t __i2400ms_rx_get_size(struct i2400ms *i2400ms)
{
int ret, cnt, val;
ssize_t rx_size;
unsigned xfer_size_addr;
struct sdio_func *func = i2400ms->func;
struct device *dev = &i2400ms->func->dev;
d_fnstart(7, dev, "(i2400ms %p)\n", i2400ms);
xfer_size_addr = I2400MS_INTR_GET_SIZE_ADDR;
rx_size = 0;
for (cnt = 0; cnt < 3; cnt++) {
val = sdio_readb(func, xfer_size_addr + cnt, &ret);
if (ret < 0) {
dev_err(dev, "RX: Can't read byte %d of RX size from "
"0x%08x: %d\n", cnt, xfer_size_addr + cnt, ret);
rx_size = ret;
goto error_read;
}
rx_size = rx_size << 8 | (val & 0xff);
}
d_printf(6, dev, "RX: rx_size is %ld\n", (long) rx_size);
error_read:
d_fnend(7, dev, "(i2400ms %p) = %ld\n", i2400ms, (long) rx_size);
return rx_size;
}
/*
* Read data from the device (when in normal)
*
* Allocate an SKB of the right size, read the data in and then
* deliver it to the generic layer.
*
* We also check for a reboot barker. That means the device died and
* we have to reboot it.
*/
static
void i2400ms_rx(struct i2400ms *i2400ms)
{
int ret;
struct sdio_func *func = i2400ms->func;
struct device *dev = &func->dev;
struct i2400m *i2400m = &i2400ms->i2400m;
struct sk_buff *skb;
ssize_t rx_size;
d_fnstart(7, dev, "(i2400ms %p)\n", i2400ms);
rx_size = __i2400ms_rx_get_size(i2400ms);
if (rx_size < 0) {
ret = rx_size;
goto error_get_size;
}
/*
* Hardware quirk: make sure to clear the INTR status register
* AFTER getting the data transfer size.
*/
sdio_writeb(func, 1, I2400MS_INTR_CLEAR_ADDR, &ret);
ret = -ENOMEM;
skb = alloc_skb(rx_size, GFP_ATOMIC);
if (NULL == skb) {
dev_err(dev, "RX: unable to alloc skb\n");
goto error_alloc_skb;
}
ret = sdio_memcpy_fromio(func, skb->data,
I2400MS_DATA_ADDR, rx_size);
if (ret < 0) {
dev_err(dev, "RX: SDIO data read failed: %d\n", ret);
goto error_memcpy_fromio;
}
rmb(); /* make sure we get boot_mode from dev_reset_handle */
if (unlikely(i2400m->boot_mode == 1)) {
spin_lock(&i2400m->rx_lock);
i2400ms->bm_ack_size = rx_size;
spin_unlock(&i2400m->rx_lock);
memcpy(i2400m->bm_ack_buf, skb->data, rx_size);
wake_up(&i2400ms->bm_wfa_wq);
d_printf(5, dev, "RX: SDIO boot mode message\n");
kfree_skb(skb);
goto out;
}
ret = -EIO;
if (unlikely(rx_size < sizeof(__le32))) {
dev_err(dev, "HW BUG? only %zu bytes received\n", rx_size);
goto error_bad_size;
}
if (likely(i2400m_is_d2h_barker(skb->data))) {
skb_put(skb, rx_size);
i2400m_rx(i2400m, skb);
} else if (unlikely(i2400m_is_boot_barker(i2400m,
skb->data, rx_size))) {
ret = i2400m_dev_reset_handle(i2400m, "device rebooted");
dev_err(dev, "RX: SDIO reboot barker\n");
kfree_skb(skb);
} else {
i2400m_unknown_barker(i2400m, skb->data, rx_size);
kfree_skb(skb);
}
out:
d_fnend(7, dev, "(i2400ms %p) = void\n", i2400ms);
return;
error_memcpy_fromio:
kfree_skb(skb);
error_alloc_skb:
error_get_size:
error_bad_size:
d_fnend(7, dev, "(i2400ms %p) = %d\n", i2400ms, ret);
}
/*
* Process an interrupt from the SDIO card
*
* FIXME: need to process other events that are not just ready-to-read
*
* Checks there is data ready and then proceeds to read it.
*/
static
void i2400ms_irq(struct sdio_func *func)
{
int ret;
struct i2400ms *i2400ms = sdio_get_drvdata(func);
struct device *dev = &func->dev;
int val;
d_fnstart(6, dev, "(i2400ms %p)\n", i2400ms);
val = sdio_readb(func, I2400MS_INTR_STATUS_ADDR, &ret);
if (ret < 0) {
dev_err(dev, "RX: Can't read interrupt status: %d\n", ret);
goto error_no_irq;
}
if (!val) {
dev_err(dev, "RX: BUG? got IRQ but no interrupt ready?\n");
goto error_no_irq;
}
i2400ms_rx(i2400ms);
error_no_irq:
d_fnend(6, dev, "(i2400ms %p) = void\n", i2400ms);
}
/*
* Setup SDIO RX
*
* Hooks up the IRQ handler and then enables IRQs.
*/
int i2400ms_rx_setup(struct i2400ms *i2400ms)
{
int result;
struct sdio_func *func = i2400ms->func;
struct device *dev = &func->dev;
struct i2400m *i2400m = &i2400ms->i2400m;
d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
init_waitqueue_head(&i2400ms->bm_wfa_wq);
spin_lock(&i2400m->rx_lock);
i2400ms->bm_wait_result = -EINPROGRESS;
/*
* Before we are about to enable the RX interrupt, make sure
* bm_ack_size is cleared to -EINPROGRESS which indicates
* no RX interrupt happened yet or the previous interrupt
* has been handled, we are ready to take the new interrupt
*/
i2400ms->bm_ack_size = -EINPROGRESS;
spin_unlock(&i2400m->rx_lock);
sdio_claim_host(func);
result = sdio_claim_irq(func, i2400ms_irq);
if (result < 0) {
dev_err(dev, "Cannot claim IRQ: %d\n", result);
goto error_irq_claim;
}
result = 0;
sdio_writeb(func, 1, I2400MS_INTR_ENABLE_ADDR, &result);
if (result < 0) {
sdio_release_irq(func);
dev_err(dev, "Failed to enable interrupts %d\n", result);
}
error_irq_claim:
sdio_release_host(func);
d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
return result;
}
/*
* Tear down SDIO RX
*
* Disables IRQs in the device and removes the IRQ handler.
*/
void i2400ms_rx_release(struct i2400ms *i2400ms)
{
int result;
struct sdio_func *func = i2400ms->func;
struct device *dev = &func->dev;
struct i2400m *i2400m = &i2400ms->i2400m;
d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
spin_lock(&i2400m->rx_lock);
i2400ms->bm_ack_size = -EINTR;
spin_unlock(&i2400m->rx_lock);
wake_up_all(&i2400ms->bm_wfa_wq);
sdio_claim_host(func);
sdio_writeb(func, 0, I2400MS_INTR_ENABLE_ADDR, &result);
sdio_release_irq(func);
sdio_release_host(func);
d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
}
/*
* Intel Wireless WiMAX Connection 2400m
* SDIO TX transaction backends
*
*
* Copyright (C) 2007-2008 Intel Corporation. All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* * Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* * Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
* * Neither the name of Intel Corporation nor the names of its
* contributors may be used to endorse or promote products derived
* from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
* A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
* OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
* SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
* DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
* THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
* OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
*
* Intel Corporation <linux-wimax@intel.com>
* Dirk Brandewie <dirk.j.brandewie@intel.com>
* - Initial implementation
*
*
* Takes the TX messages in the i2400m's driver TX FIFO and sends them
* to the device until there are no more.
*
* If we fail sending the message, we just drop it. There isn't much
* we can do at this point. Most of the traffic is network, which has
* recovery methods for dropped packets.
*
* The SDIO functions are not atomic, so we can't run from the context
* where i2400m->bus_tx_kick() [i2400ms_bus_tx_kick()] is being called
* (some times atomic). Thus, the actual TX work is deferred to a
* workqueue.
*
* ROADMAP
*
* i2400ms_bus_tx_kick()
* i2400ms_tx_submit() [through workqueue]
*
* i2400m_tx_setup()
*
* i2400m_tx_release()
*/
#include <linux/mmc/sdio_func.h>
#include "i2400m-sdio.h"
#define D_SUBMODULE tx
#include "sdio-debug-levels.h"
/*
* Pull TX transations from the TX FIFO and send them to the device
* until there are no more.
*/
static
void i2400ms_tx_submit(struct work_struct *ws)
{
int result;
struct i2400ms *i2400ms = container_of(ws, struct i2400ms, tx_worker);
struct i2400m *i2400m = &i2400ms->i2400m;
struct sdio_func *func = i2400ms->func;
struct device *dev = &func->dev;
struct i2400m_msg_hdr *tx_msg;
size_t tx_msg_size;
d_fnstart(4, dev, "(i2400ms %p, i2400m %p)\n", i2400ms, i2400ms);
while (NULL != (tx_msg = i2400m_tx_msg_get(i2400m, &tx_msg_size))) {
d_printf(2, dev, "TX: submitting %zu bytes\n", tx_msg_size);
d_dump(5, dev, tx_msg, tx_msg_size);
sdio_claim_host(func);
result = sdio_memcpy_toio(func, 0, tx_msg, tx_msg_size);
sdio_release_host(func);
i2400m_tx_msg_sent(i2400m);
if (result < 0) {
dev_err(dev, "TX: cannot submit TX; tx_msg @%zu %zu B:"
" %d\n", (void *) tx_msg - i2400m->tx_buf,
tx_msg_size, result);
}
if (result == -ETIMEDOUT) {
i2400m_error_recovery(i2400m);
break;
}
d_printf(2, dev, "TX: %zub submitted\n", tx_msg_size);
}
d_fnend(4, dev, "(i2400ms %p) = void\n", i2400ms);
}
/*
* The generic driver notifies us that there is data ready for TX
*
* Schedule a run of i2400ms_tx_submit() to handle it.
*/
void i2400ms_bus_tx_kick(struct i2400m *i2400m)
{
struct i2400ms *i2400ms = container_of(i2400m, struct i2400ms, i2400m);
struct device *dev = &i2400ms->func->dev;
unsigned long flags;
d_fnstart(3, dev, "(i2400m %p) = void\n", i2400m);
/* schedule tx work, this is because tx may block, therefore
* it has to run in a thread context.
*/
spin_lock_irqsave(&i2400m->tx_lock, flags);
if (i2400ms->tx_workqueue != NULL)
queue_work(i2400ms->tx_workqueue, &i2400ms->tx_worker);
spin_unlock_irqrestore(&i2400m->tx_lock, flags);
d_fnend(3, dev, "(i2400m %p) = void\n", i2400m);
}
int i2400ms_tx_setup(struct i2400ms *i2400ms)
{
int result;
struct device *dev = &i2400ms->func->dev;
struct i2400m *i2400m = &i2400ms->i2400m;
struct workqueue_struct *tx_workqueue;
unsigned long flags;
d_fnstart(5, dev, "(i2400ms %p)\n", i2400ms);
INIT_WORK(&i2400ms->tx_worker, i2400ms_tx_submit);
snprintf(i2400ms->tx_wq_name, sizeof(i2400ms->tx_wq_name),
"%s-tx", i2400m->wimax_dev.name);
tx_workqueue =
create_singlethread_workqueue(i2400ms->tx_wq_name);
if (tx_workqueue == NULL) {
dev_err(dev, "TX: failed to create workqueue\n");
result = -ENOMEM;
} else
result = 0;
spin_lock_irqsave(&i2400m->tx_lock, flags);
i2400ms->tx_workqueue = tx_workqueue;
spin_unlock_irqrestore(&i2400m->tx_lock, flags);
d_fnend(5, dev, "(i2400ms %p) = %d\n", i2400ms, result);
return result;
}
void i2400ms_tx_release(struct i2400ms *i2400ms)
{
struct i2400m *i2400m = &i2400ms->i2400m;
struct workqueue_struct *tx_workqueue;
unsigned long flags;
tx_workqueue = i2400ms->tx_workqueue;
spin_lock_irqsave(&i2400m->tx_lock, flags);
i2400ms->tx_workqueue = NULL;
spin_unlock_irqrestore(&i2400m->tx_lock, flags);
if (tx_workqueue)
destroy_workqueue(tx_workqueue);
}
This diff is collapsed.
......@@ -276,7 +276,6 @@ source "drivers/net/wireless/hostap/Kconfig"
source "drivers/net/wireless/ipw2x00/Kconfig"
source "drivers/net/wireless/iwlwifi/Kconfig"
source "drivers/net/wireless/iwlegacy/Kconfig"
source "drivers/net/wireless/iwmc3200wifi/Kconfig"
source "drivers/net/wireless/libertas/Kconfig"
source "drivers/net/wireless/orinoco/Kconfig"
source "drivers/net/wireless/p54/Kconfig"
......
......@@ -53,8 +53,6 @@ obj-$(CONFIG_MAC80211_HWSIM) += mac80211_hwsim.o
obj-$(CONFIG_WL_TI) += ti/
obj-$(CONFIG_IWM) += iwmc3200wifi/
obj-$(CONFIG_MWIFIEX) += mwifiex/
obj-$(CONFIG_BRCMFMAC) += brcm80211/
......
......@@ -64,3 +64,11 @@ config ATH5K_PCI
---help---
This adds support for PCI type chipsets of the 5xxx Atheros
family.
config ATH5K_TEST_CHANNELS
bool "Enables testing channels on ath5k"
depends on ATH5K && CFG80211_CERTIFICATION_ONUS
---help---
This enables non-standard IEEE 802.11 channels on ath5k, which
can be used for research purposes. This option should be disabled
unless doing research.
......@@ -74,10 +74,6 @@ bool ath5k_modparam_nohwcrypt;
module_param_named(nohwcrypt, ath5k_modparam_nohwcrypt, bool, S_IRUGO);
MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
static bool modparam_all_channels;
module_param_named(all_channels, modparam_all_channels, bool, S_IRUGO);
MODULE_PARM_DESC(all_channels, "Expose all channels the device can use.");
static bool modparam_fastchanswitch;
module_param_named(fastchanswitch, modparam_fastchanswitch, bool, S_IRUGO);
MODULE_PARM_DESC(fastchanswitch, "Enable fast channel switching for AR2413/AR5413 radios.");
......@@ -258,8 +254,15 @@ static int ath5k_reg_notifier(struct wiphy *wiphy, struct regulatory_request *re
\********************/
/*
* Returns true for the channel numbers used without all_channels modparam.
* Returns true for the channel numbers used.
*/
#ifdef CONFIG_ATH5K_TEST_CHANNELS
static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band)
{
return true;
}
#else
static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band)
{
if (band == IEEE80211_BAND_2GHZ && chan <= 14)
......@@ -276,6 +279,7 @@ static bool ath5k_is_standard_channel(short chan, enum ieee80211_band band)
/* 802.11j 4.9GHz (20MHz) */
(chan == 184 || chan == 188 || chan == 192 || chan == 196));
}
#endif
static unsigned int
ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
......@@ -316,8 +320,7 @@ ath5k_setup_channels(struct ath5k_hw *ah, struct ieee80211_channel *channels,
if (!ath5k_channel_ok(ah, &channels[count]))
continue;
if (!modparam_all_channels &&
!ath5k_is_standard_channel(ch, band))
if (!ath5k_is_standard_channel(ch, band))
continue;
count++;
......
......@@ -3627,6 +3627,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
wiphy->cipher_suites = cipher_suites;
wiphy->n_cipher_suites = ARRAY_SIZE(cipher_suites);
#ifdef CONFIG_PM
wiphy->wowlan.flags = WIPHY_WOWLAN_MAGIC_PKT |
WIPHY_WOWLAN_DISCONNECT |
WIPHY_WOWLAN_GTK_REKEY_FAILURE |
......@@ -3636,6 +3637,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
wiphy->wowlan.n_patterns = WOW_MAX_FILTERS_PER_LIST;
wiphy->wowlan.pattern_min_len = 1;
wiphy->wowlan.pattern_max_len = WOW_PATTERN_SIZE;
#endif
wiphy->max_sched_scan_ssids = MAX_PROBED_SSIDS;
......
......@@ -35,6 +35,10 @@ static const struct platform_device_id ath9k_platform_id_table[] = {
.name = "ar934x_wmac",
.driver_data = AR9300_DEVID_AR9340,
},
{
.name = "qca955x_wmac",
.driver_data = AR9300_DEVID_QCA955X,
},
{},
};
......
......@@ -159,14 +159,11 @@ static bool ar9003_hw_calibrate(struct ath_hw *ah,
}
}
/* Do NF cal only at longer intervals */
if (longcal) {
/*
* Get the value from the previous NF cal and update
* history buffer.
*/
ath9k_hw_getnf(ah, chan);
/*
* Do NF cal only at longer intervals. Get the value from
* the previous NF cal and update history buffer.
*/
if (longcal && ath9k_hw_getnf(ah, chan)) {
/*
* Load the NF from history buffer of the current channel.
* NF is slow time-variant, so it is OK to use a historical
......
......@@ -3509,7 +3509,7 @@ static void ar9003_hw_xpa_bias_level_apply(struct ath_hw *ah, bool is2ghz)
if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah))
REG_RMW_FIELD(ah, AR_CH0_TOP2, AR_CH0_TOP2_XPABIASLVL, bias);
else if (AR_SREV_9462(ah))
else if (AR_SREV_9462(ah) || AR_SREV_9550(ah))
REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
else {
REG_RMW_FIELD(ah, AR_CH0_TOP, AR_CH0_TOP_XPABIASLVL, bias);
......@@ -3591,6 +3591,9 @@ static void ar9003_hw_ant_ctrl_apply(struct ath_hw *ah, bool is2ghz)
if (AR_SREV_9462(ah)) {
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
AR_SWITCH_TABLE_COM_AR9462_ALL, value);
} else if (AR_SREV_9550(ah)) {
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
AR_SWITCH_TABLE_COM_AR9550_ALL, value);
} else
REG_RMW_FIELD(ah, AR_PHY_SWITCH_COM,
AR_SWITCH_TABLE_COM_ALL, value);
......@@ -3957,7 +3960,7 @@ static void ath9k_hw_ar9300_set_board_values(struct ath_hw *ah,
ar9003_hw_drive_strength_apply(ah);
ar9003_hw_atten_apply(ah, chan);
ar9003_hw_quick_drop_apply(ah, chan->channel);
if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah))
if (!AR_SREV_9330(ah) && !AR_SREV_9340(ah) && !AR_SREV_9550(ah))
ar9003_hw_internal_regulator_apply(ah);
if (AR_SREV_9485(ah) || AR_SREV_9330(ah) || AR_SREV_9340(ah))
ar9003_hw_apply_tuning_caps(ah);
......
......@@ -21,6 +21,7 @@
#include "ar9340_initvals.h"
#include "ar9330_1p1_initvals.h"
#include "ar9330_1p2_initvals.h"
#include "ar955x_1p0_initvals.h"
#include "ar9580_1p0_initvals.h"
#include "ar9462_2p0_initvals.h"
......@@ -327,7 +328,61 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ,
ARRAY_SIZE(AR9462_BBC_TXIFR_COEFFJ), 2);
} else if (AR_SREV_9550(ah)) {
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
ar955x_1p0_mac_core,
ARRAY_SIZE(ar955x_1p0_mac_core), 2);
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_POST],
ar955x_1p0_mac_postamble,
ARRAY_SIZE(ar955x_1p0_mac_postamble), 5);
/* bb */
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_PRE], NULL, 0, 0);
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_CORE],
ar955x_1p0_baseband_core,
ARRAY_SIZE(ar955x_1p0_baseband_core), 2);
INIT_INI_ARRAY(&ah->iniBB[ATH_INI_POST],
ar955x_1p0_baseband_postamble,
ARRAY_SIZE(ar955x_1p0_baseband_postamble), 5);
/* radio */
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_PRE], NULL, 0, 0);
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_CORE],
ar955x_1p0_radio_core,
ARRAY_SIZE(ar955x_1p0_radio_core), 2);
INIT_INI_ARRAY(&ah->iniRadio[ATH_INI_POST],
ar955x_1p0_radio_postamble,
ARRAY_SIZE(ar955x_1p0_radio_postamble), 5);
/* soc */
INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_PRE],
ar955x_1p0_soc_preamble,
ARRAY_SIZE(ar955x_1p0_soc_preamble), 2);
INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_CORE], NULL, 0, 0);
INIT_INI_ARRAY(&ah->iniSOC[ATH_INI_POST],
ar955x_1p0_soc_postamble,
ARRAY_SIZE(ar955x_1p0_soc_postamble), 5);
/* rx/tx gain */
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar955x_1p0_common_wo_xlna_rx_gain_table,
ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_table),
2);
INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
ar955x_1p0_common_wo_xlna_rx_gain_bounds,
ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_bounds),
5);
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar955x_1p0_modes_xpa_tx_gain_table,
ARRAY_SIZE(ar955x_1p0_modes_xpa_tx_gain_table),
9);
/* Fast clock modal settings */
INIT_INI_ARRAY(&ah->iniModesFastClock,
ar955x_1p0_modes_fast_clock,
ARRAY_SIZE(ar955x_1p0_modes_fast_clock), 3);
} else if (AR_SREV_9580(ah)) {
/* mac */
INIT_INI_ARRAY(&ah->iniMac[ATH_INI_PRE], NULL, 0, 0);
......@@ -470,6 +525,11 @@ static void ar9003_tx_gain_table_mode0(struct ath_hw *ah)
ar9485_modes_lowest_ob_db_tx_gain_1_1,
ARRAY_SIZE(ar9485_modes_lowest_ob_db_tx_gain_1_1),
5);
else if (AR_SREV_9550(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar955x_1p0_modes_xpa_tx_gain_table,
ARRAY_SIZE(ar955x_1p0_modes_xpa_tx_gain_table),
9);
else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9580_1p0_lowest_ob_db_tx_gain_table,
......@@ -514,6 +574,11 @@ static void ar9003_tx_gain_table_mode1(struct ath_hw *ah)
ar9580_1p0_high_ob_db_tx_gain_table,
ARRAY_SIZE(ar9580_1p0_high_ob_db_tx_gain_table),
5);
else if (AR_SREV_9550(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar955x_1p0_modes_no_xpa_tx_gain_table,
ARRAY_SIZE(ar955x_1p0_modes_no_xpa_tx_gain_table),
9);
else if (AR_SREV_9462_20(ah))
INIT_INI_ARRAY(&ah->iniModesTxGain,
ar9462_modes_high_ob_db_tx_gain_table_2p0,
......@@ -635,7 +700,16 @@ static void ar9003_rx_gain_table_mode0(struct ath_hw *ah)
ar9485Common_wo_xlna_rx_gain_1_1,
ARRAY_SIZE(ar9485Common_wo_xlna_rx_gain_1_1),
2);
else if (AR_SREV_9580(ah))
else if (AR_SREV_9550(ah)) {
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar955x_1p0_common_rx_gain_table,
ARRAY_SIZE(ar955x_1p0_common_rx_gain_table),
2);
INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
ar955x_1p0_common_rx_gain_bounds,
ARRAY_SIZE(ar955x_1p0_common_rx_gain_bounds),
5);
} else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9580_1p0_rx_gain_table,
ARRAY_SIZE(ar9580_1p0_rx_gain_table),
......@@ -679,7 +753,16 @@ static void ar9003_rx_gain_table_mode1(struct ath_hw *ah)
ar9462_common_wo_xlna_rx_gain_table_2p0,
ARRAY_SIZE(ar9462_common_wo_xlna_rx_gain_table_2p0),
2);
else if (AR_SREV_9580(ah))
else if (AR_SREV_9550(ah)) {
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar955x_1p0_common_wo_xlna_rx_gain_table,
ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_table),
2);
INIT_INI_ARRAY(&ah->ini_modes_rx_gain_bounds,
ar955x_1p0_common_wo_xlna_rx_gain_bounds,
ARRAY_SIZE(ar955x_1p0_common_wo_xlna_rx_gain_bounds),
5);
} else if (AR_SREV_9580(ah))
INIT_INI_ARRAY(&ah->iniModesRxGain,
ar9580_1p0_wo_xlna_rx_gain_table,
ARRAY_SIZE(ar9580_1p0_wo_xlna_rx_gain_table),
......
......@@ -1015,12 +1015,9 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)
return;
if (mci->is_2g) {
if (!force) {
ar9003_mci_send_2g5g_status(ah, true);
ar9003_mci_send_lna_transfer(ah, true);
udelay(5);
}
ar9003_mci_send_2g5g_status(ah, true);
ar9003_mci_send_lna_transfer(ah, true);
udelay(5);
REG_CLR_BIT(ah, AR_MCI_TX_CTRL,
AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
......@@ -1030,10 +1027,8 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)
if (!(mci->config & ATH_MCI_CONFIG_DISABLE_OSLA))
ar9003_mci_osla_setup(ah, true);
} else {
if (!force) {
ar9003_mci_send_lna_take(ah, true);
udelay(5);
}
ar9003_mci_send_lna_take(ah, true);
udelay(5);
REG_SET_BIT(ah, AR_MCI_TX_CTRL,
AR_MCI_TX_CTRL_DISABLE_LNA_UPDATE);
......@@ -1041,8 +1036,7 @@ void ar9003_mci_2g5g_switch(struct ath_hw *ah, bool force)
AR_BTCOEX_CTRL_BT_OWN_SPDT_CTRL);
ar9003_mci_osla_setup(ah, false);
if (!force)
ar9003_mci_send_2g5g_status(ah, true);
ar9003_mci_send_2g5g_status(ah, true);
}
}
......
......@@ -211,7 +211,7 @@ static int ar9003_paprd_setup_single_table(struct ath_hw *ah)
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_NUM_CORR_STAGES, 7);
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_MIN_LOOPBACK_DEL, 1);
if (AR_SREV_9485(ah) || AR_SREV_9462(ah))
if (AR_SREV_9485(ah) || AR_SREV_9462(ah) || AR_SREV_9550(ah))
REG_RMW_FIELD(ah, AR_PHY_PAPRD_TRAINER_CNTL3,
AR_PHY_PAPRD_TRAINER_CNTL3_CF_PAPRD_QUICK_DROP,
-3);
......
This diff is collapsed.
......@@ -636,8 +636,8 @@
#define AR_CH0_TOP (AR_SREV_9300(ah) ? 0x16288 : \
((AR_SREV_9462(ah) ? 0x1628c : 0x16280)))
#define AR_CH0_TOP_XPABIASLVL (0x300)
#define AR_CH0_TOP_XPABIASLVL_S (8)
#define AR_CH0_TOP_XPABIASLVL (AR_SREV_9550(ah) ? 0x3c0 : 0x300)
#define AR_CH0_TOP_XPABIASLVL_S (AR_SREV_9550(ah) ? 6 : 8)
#define AR_CH0_THERM (AR_SREV_9300(ah) ? 0x16290 : \
((AR_SREV_9485(ah) ? 0x1628c : 0x16294)))
......@@ -650,6 +650,8 @@
#define AR_SWITCH_TABLE_COM_ALL_S (0)
#define AR_SWITCH_TABLE_COM_AR9462_ALL (0xffffff)
#define AR_SWITCH_TABLE_COM_AR9462_ALL_S (0)
#define AR_SWITCH_TABLE_COM_AR9550_ALL (0xffffff)
#define AR_SWITCH_TABLE_COM_AR9550_ALL_S (0)
#define AR_SWITCH_TABLE_COM_SPDT (0x00f00000)
#define AR_SWITCH_TABLE_COM_SPDT_ALL (0x0000fff0)
#define AR_SWITCH_TABLE_COM_SPDT_ALL_S (4)
......
This diff is collapsed.
......@@ -481,6 +481,7 @@ void ath9k_btcoex_timer_resume(struct ath_softc *sc);
void ath9k_btcoex_timer_pause(struct ath_softc *sc);
void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status);
u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen);
void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc);
#else
static inline int ath9k_init_btcoex(struct ath_softc *sc)
{
......@@ -504,6 +505,9 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc,
{
return 0;
}
static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
{
}
#endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
/********************/
......
This diff is collapsed.
This diff is collapsed.
......@@ -48,6 +48,7 @@
#define AR9300_DEVID_AR9580 0x0033
#define AR9300_DEVID_AR9462 0x0034
#define AR9300_DEVID_AR9330 0x0035
#define AR9300_DEVID_QCA955X 0x0038
#define AR5416_AR9100_DEVID 0x000b
......@@ -818,6 +819,7 @@ struct ath_hw {
struct ar5416IniArray iniModesFastClock;
struct ar5416IniArray iniAdditional;
struct ar5416IniArray iniModesRxGain;
struct ar5416IniArray ini_modes_rx_gain_bounds;
struct ar5416IniArray iniModesTxGain;
struct ar5416IniArray iniCckfirNormal;
struct ar5416IniArray iniCckfirJapan2484;
......
......@@ -810,7 +810,7 @@ void ath9k_hw_enable_interrupts(struct ath_hw *ah)
return;
}
if (AR_SREV_9340(ah))
if (AR_SREV_9340(ah) || AR_SREV_9550(ah))
sync_default &= ~AR_INTR_SYNC_HOST1_FATAL;
async_mask = AR_INTR_MAC_IRQ;
......
......@@ -646,6 +646,7 @@ enum ath9k_rx_filter {
ATH9K_RX_FILTER_PHYRADAR = 0x00002000,
ATH9K_RX_FILTER_MCAST_BCAST_ALL = 0x00008000,
ATH9K_RX_FILTER_CONTROL_WRAPPER = 0x00080000,
ATH9K_RX_FILTER_4ADDRESS = 0x00100000,
};
#define ATH9K_RATESERIES_RTS_CTS 0x0001
......
This diff is collapsed.
......@@ -174,8 +174,8 @@ static void ath_mci_update_scheme(struct ath_softc *sc)
btcoex->btcoex_period >>= 1;
}
ath9k_hw_btcoex_disable(sc->sc_ah);
ath9k_btcoex_timer_pause(sc);
ath9k_hw_btcoex_disable(sc->sc_ah);
if (IS_CHAN_5GHZ(sc->sc_ah->curchan))
return;
......
......@@ -430,6 +430,9 @@ u32 ath_calcrxfilter(struct ath_softc *sc)
rfilt |= ATH9K_RX_FILTER_MCAST_BCAST_ALL;
}
if (AR_SREV_9550(sc->sc_ah))
rfilt |= ATH9K_RX_FILTER_4ADDRESS;
return rfilt;
}
......
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
This diff is collapsed.
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment