#define BCMA_GPIO_MAX_PINS 32
-static inline struct bcma_drv_cc *bcma_gpio_get_cc(struct gpio_chip *chip)
-{
- return container_of(chip, struct bcma_drv_cc, gpio);
-}
-
static int bcma_gpio_get_value(struct gpio_chip *chip, unsigned gpio)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
return !!bcma_chipco_gpio_in(cc, 1 << gpio);
}
static void bcma_gpio_set_value(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
}
static int bcma_gpio_direction_input(struct gpio_chip *chip, unsigned gpio)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
bcma_chipco_gpio_outen(cc, 1 << gpio, 0);
return 0;
static int bcma_gpio_direction_output(struct gpio_chip *chip, unsigned gpio,
int value)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
bcma_chipco_gpio_outen(cc, 1 << gpio, 1 << gpio);
bcma_chipco_gpio_out(cc, 1 << gpio, value ? 1 << gpio : 0);
static int bcma_gpio_request(struct gpio_chip *chip, unsigned gpio)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
bcma_chipco_gpio_control(cc, 1 << gpio, 0);
/* clear pulldown */
static void bcma_gpio_free(struct gpio_chip *chip, unsigned gpio)
{
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(chip);
+ struct bcma_drv_cc *cc = gpiochip_get_data(chip);
/* clear pullup */
bcma_chipco_gpio_pullup(cc, 1 << gpio, 0);
static void bcma_gpio_irq_unmask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(gc);
+ struct bcma_drv_cc *cc = gpiochip_get_data(gc);
int gpio = irqd_to_hwirq(d);
u32 val = bcma_chipco_gpio_in(cc, BIT(gpio));
static void bcma_gpio_irq_mask(struct irq_data *d)
{
struct gpio_chip *gc = irq_data_get_irq_chip_data(d);
- struct bcma_drv_cc *cc = bcma_gpio_get_cc(gc);
+ struct bcma_drv_cc *cc = gpiochip_get_data(gc);
int gpio = irqd_to_hwirq(d);
bcma_chipco_gpio_intmask(cc, BIT(gpio), 0);
chip->direction_input = bcma_gpio_direction_input;
chip->direction_output = bcma_gpio_direction_output;
chip->owner = THIS_MODULE;
- chip->dev = bcma_bus_get_host_dev(bus);
+ chip->parent = bcma_bus_get_host_dev(bus);
#if IS_BUILTIN(CONFIG_OF)
if (cc->core->bus->hosttype == BCMA_HOSTTYPE_SOC)
chip->of_node = cc->core->dev.of_node;
case BCMA_CHIP_ID_BCM4707:
case BCMA_CHIP_ID_BCM5357:
case BCMA_CHIP_ID_BCM53572:
+ case BCMA_CHIP_ID_BCM47094:
chip->ngpio = 32;
break;
default:
else
chip->base = -1;
- err = gpiochip_add(chip);
+ err = gpiochip_add_data(chip, cc);
if (err)
return err;
#include "chip.h"
#include "firmware.h"
- #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2000)
- #define CTL_DONE_TIMEOUT msecs_to_jiffies(2000)
+ #define DCMD_RESP_TIMEOUT msecs_to_jiffies(2500)
+ #define CTL_DONE_TIMEOUT msecs_to_jiffies(2500)
#ifdef DEBUG
const struct sdiod_drive_str *str_tab = NULL;
u32 str_mask;
u32 str_shift;
- u32 base;
u32 i;
u32 drivestrength_sel = 0;
u32 cc_data_temp;
}
if (str_tab != NULL) {
+ struct brcmf_core *pmu = brcmf_chip_get_pmu(ci);
+
for (i = 0; str_tab[i].strength != 0; i++) {
if (drivestrength >= str_tab[i].strength) {
drivestrength_sel = str_tab[i].sel;
break;
}
}
- base = brcmf_chip_get_chipcommon(ci)->base;
- addr = CORE_CC_REG(base, chipcontrol_addr);
+ addr = CORE_CC_REG(pmu->base, chipcontrol_addr);
brcmf_sdiod_regwl(sdiodev, addr, 1, NULL);
cc_data_temp = brcmf_sdiod_regrl(sdiodev, addr, NULL);
cc_data_temp &= ~str_mask;
goto fail;
/* set PMUControl so a backplane reset does PMU state reload */
- reg_addr = CORE_CC_REG(brcmf_chip_get_chipcommon(bus->ci)->base,
- pmucontrol);
+ reg_addr = CORE_CC_REG(brcmf_chip_get_pmu(bus->ci)->base, pmucontrol);
reg_val = brcmf_sdiod_regrl(bus->sdiodev, reg_addr, &err);
if (err)
goto fail;
goto fail;
}
+ /* allocate scatter-gather table. sg support
+ * will be disabled upon allocation failure.
+ */
+ brcmf_sdiod_sgtable_alloc(bus->sdiodev);
+
/* Query the F2 block size, set roundup accordingly */
bus->blocksize = bus->sdiodev->func[2]->cur_blksize;
bus->roundup = min(max_roundup, bus->blocksize);
*
* Copyright(c) 2005 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of version 2 of the GNU General Public License as
return 0;
}
-static int rs_collect_tx_data(struct iwl_mvm *mvm,
- struct iwl_lq_sta *lq_sta,
- struct iwl_scale_tbl_info *tbl,
- int scale_index, int attempts, int successes,
- u8 reduced_txp)
+static int rs_collect_tpc_data(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl,
+ int scale_index, int attempts, int successes,
+ u8 reduced_txp)
+{
+ struct iwl_rate_scale_data *window = NULL;
+
+ if (WARN_ON_ONCE(reduced_txp > TPC_MAX_REDUCTION))
+ return -EINVAL;
+
+ window = &tbl->tpc_win[reduced_txp];
+ return _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes,
+ window);
+}
+
+static int rs_collect_tlc_data(struct iwl_mvm *mvm,
+ struct iwl_lq_sta *lq_sta,
+ struct iwl_scale_tbl_info *tbl,
+ int scale_index, int attempts, int successes)
{
struct iwl_rate_scale_data *window = NULL;
- int ret;
if (scale_index < 0 || scale_index >= IWL_RATE_COUNT)
return -EINVAL;
/* Select window for current tx bit rate */
window = &(tbl->win[scale_index]);
-
- ret = _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes,
- window);
- if (ret)
- return ret;
-
- if (WARN_ON_ONCE(reduced_txp > TPC_MAX_REDUCTION))
- return -EINVAL;
-
- window = &tbl->tpc_win[reduced_txp];
return _rs_collect_tx_data(mvm, tbl, scale_index, attempts, successes,
window);
}
* first index into rate scale table.
*/
if (info->flags & IEEE80211_TX_STAT_AMPDU) {
- /* ampdu_ack_len = 0 marks no BA was received. In this case
- * treat it as a single frame loss as we don't want the success
- * ratio to dip too quickly because a BA wasn't received
+ rs_collect_tpc_data(mvm, lq_sta, curr_tbl, lq_rate.index,
+ info->status.ampdu_len,
+ info->status.ampdu_ack_len,
+ reduced_txp);
+
+ /* ampdu_ack_len = 0 marks no BA was received. For TLC, treat
+ * it as a single frame loss as we don't want the success ratio
+ * to dip too quickly because a BA wasn't received.
+ * For TPC, there's no need for this optimisation since we want
+ * to recover very quickly from a bad power reduction and,
+ * therefore we'd like the success ratio to get an immediate hit
+ * when failing to get a BA, so we'd switch back to a lower or
+ * zero power reduction. When FW transmits agg with a rate
+ * different from the initial rate, it will not use reduced txp
+ * and will send BA notification twice (one empty with reduced
+ * txp equal to the value from LQ and one with reduced txp 0).
+ * We need to update counters for each txp level accordingly.
*/
if (info->status.ampdu_ack_len == 0)
info->status.ampdu_len = 1;
- rs_collect_tx_data(mvm, lq_sta, curr_tbl, lq_rate.index,
- info->status.ampdu_len,
- info->status.ampdu_ack_len,
- reduced_txp);
+ rs_collect_tlc_data(mvm, lq_sta, curr_tbl, lq_rate.index,
+ info->status.ampdu_len,
+ info->status.ampdu_ack_len);
/* Update success/fail counts if not searching for new mode */
if (lq_sta->rs_state == RS_STATE_STAY_IN_COLUMN) {
else
continue;
- rs_collect_tx_data(mvm, lq_sta, tmp_tbl, lq_rate.index,
- 1, i < retries ? 0 : legacy_success,
- reduced_txp);
+ rs_collect_tpc_data(mvm, lq_sta, tmp_tbl,
+ lq_rate.index, 1,
+ i < retries ? 0 : legacy_success,
+ reduced_txp);
+ rs_collect_tlc_data(mvm, lq_sta, tmp_tbl,
+ lq_rate.index, 1,
+ i < retries ? 0 : legacy_success);
}
/* Update success/fail counts if not searching for new mode */
}
/* try decreasing first if applicable */
- if (weak != TPC_INVALID) {
+ if (sr >= RS_PERCENT(IWL_MVM_RS_TPC_SR_NO_INCREASE) &&
+ weak != TPC_INVALID) {
if (weak_tpt == IWL_INVALID_VALUE &&
(strong_tpt == IWL_INVALID_VALUE ||
current_tpt >= strong_tpt)) {
iwl_mvm_hwrate_to_tx_rate(rate_n_flags, info->band, r);
}
+ static void iwl_mvm_tx_status_check_trigger(struct iwl_mvm *mvm,
+ u32 status)
+ {
+ struct iwl_fw_dbg_trigger_tlv *trig;
+ struct iwl_fw_dbg_trigger_tx_status *status_trig;
+ int i;
+
+ if (!iwl_fw_dbg_trigger_enabled(mvm->fw, FW_DBG_TRIGGER_TX_STATUS))
+ return;
+
+ trig = iwl_fw_dbg_get_trigger(mvm->fw, FW_DBG_TRIGGER_TX_STATUS);
+ status_trig = (void *)trig->data;
+
+ if (!iwl_fw_dbg_trigger_check_stop(mvm, NULL, trig))
+ return;
+
+ for (i = 0; i < ARRAY_SIZE(status_trig->statuses); i++) {
+ /* don't collect on status 0 */
+ if (!status_trig->statuses[i].status)
+ break;
+
+ if (status_trig->statuses[i].status != (status & TX_STATUS_MSK))
+ continue;
+
+ iwl_mvm_fw_dbg_collect_trig(mvm, trig,
+ "Tx status %d was received",
+ status & TX_STATUS_MSK);
+ break;
+ }
+ }
+
static void iwl_mvm_rx_tx_cmd_single(struct iwl_mvm *mvm,
struct iwl_rx_packet *pkt)
{
break;
}
+ iwl_mvm_tx_status_check_trigger(mvm, status);
+
info->status.rates[0].count = tx_resp->failure_frame + 1;
iwl_mvm_hwrate_to_tx_status(le32_to_cpu(tx_resp->initial_rate),
info);
struct iwl_mvm_sta *mvmsta = iwl_mvm_sta_from_mac80211(sta);
mvmsta->tid_data[tid].rate_n_flags =
le32_to_cpu(tx_resp->initial_rate);
- mvmsta->tid_data[tid].reduced_tpc = tx_resp->reduced_tpc;
mvmsta->tid_data[tid].tx_time =
le16_to_cpu(tx_resp->wireless_media_time);
}
/* TODO: not accounted if the whole A-MPDU failed */
info->status.tx_time = tid_data->tx_time;
info->status.status_driver_data[0] =
- (void *)(uintptr_t)tid_data->reduced_tpc;
+ (void *)(uintptr_t)ba_notif->reduced_txp;
info->status.status_driver_data[1] =
(void *)(uintptr_t)tid_data->rate_n_flags;
}
scd_flow, ba_resp_scd_ssn, ba_notif->txed,
ba_notif->txed_2_done);
+ IWL_DEBUG_TX_REPLY(mvm, "reduced txp from ba notif %d\n",
+ ba_notif->reduced_txp);
tid_data->next_reclaimed = ba_resp_scd_ssn;
iwl_mvm_check_ratid_empty(mvm, sta, tid);
*
* Copyright(c) 2007 - 2014 Intel Corporation. All rights reserved.
* Copyright(c) 2013 - 2015 Intel Mobile Communications GmbH
+ * Copyright(c) 2016 Intel Deutschland GmbH
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of version 2 of the GNU General Public License as
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
#include <linux/module.h>
+ #include <linux/pm_runtime.h>
#include <linux/pci.h>
#include <linux/pci-aspm.h>
#include <linux/acpi.h>
{IWL_PCI_DEVICE(0x3165, 0x8110, iwl3165_2ac_cfg)},
/* 3168 Series */
+ {IWL_PCI_DEVICE(0x24FB, 0x2010, iwl3168_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FB, 0x2110, iwl3168_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24FB, 0x2050, iwl3168_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24FB, 0x2150, iwl3168_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FB, 0x0000, iwl3168_2ac_cfg)},
/* 7265 Series */
{IWL_PCI_DEVICE(0x24F3, 0x0000, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x0010, iwl8265_2ac_cfg)},
{IWL_PCI_DEVICE(0x24FD, 0x8010, iwl8265_2ac_cfg)},
+ {IWL_PCI_DEVICE(0x24FD, 0x0810, iwl8265_2ac_cfg)},
/* 9000 Series */
{IWL_PCI_DEVICE(0x9DF0, 0x2A10, iwl5165_2ac_cfg)},
if (ret)
goto out_free_drv;
+ /* if RTPM is in use, enable it in our device */
+ if (iwl_trans->runtime_pm_mode != IWL_PLAT_PM_MODE_DISABLED) {
+ pm_runtime_set_active(&pdev->dev);
+ pm_runtime_set_autosuspend_delay(&pdev->dev,
+ iwlwifi_mod_params.d0i3_entry_delay);
+ pm_runtime_use_autosuspend(&pdev->dev);
+ pm_runtime_allow(&pdev->dev);
+ }
+
return 0;
out_free_drv:
return 0;
}
- static SIMPLE_DEV_PM_OPS(iwl_dev_pm_ops, iwl_pci_suspend, iwl_pci_resume);
+ int iwl_pci_fw_enter_d0i3(struct iwl_trans *trans)
+ {
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ int ret;
+
+ if (test_bit(STATUS_FW_ERROR, &trans->status))
+ return 0;
+
+ set_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+
+ /* config the fw */
+ ret = iwl_op_mode_enter_d0i3(trans->op_mode);
+ if (ret == 1) {
+ IWL_DEBUG_RPM(trans, "aborting d0i3 entrance\n");
+ clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+ return -EBUSY;
+ }
+ if (ret)
+ goto err;
+
+ ret = wait_event_timeout(trans_pcie->d0i3_waitq,
+ test_bit(STATUS_TRANS_IDLE, &trans->status),
+ msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT));
+ if (!ret) {
+ IWL_ERR(trans, "Timeout entering D0i3\n");
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+
+ clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+
+ return 0;
+ err:
+ clear_bit(STATUS_TRANS_GOING_IDLE, &trans->status);
+ iwl_trans_fw_error(trans);
+ return ret;
+ }
+
+ int iwl_pci_fw_exit_d0i3(struct iwl_trans *trans)
+ {
+ struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+ int ret;
+
+ /* sometimes a D0i3 entry is not followed through */
+ if (!test_bit(STATUS_TRANS_IDLE, &trans->status))
+ return 0;
+
+ /* config the fw */
+ ret = iwl_op_mode_exit_d0i3(trans->op_mode);
+ if (ret)
+ goto err;
+
+ /* we clear STATUS_TRANS_IDLE only when D0I3_END command is completed */
+
+ ret = wait_event_timeout(trans_pcie->d0i3_waitq,
+ !test_bit(STATUS_TRANS_IDLE, &trans->status),
+ msecs_to_jiffies(IWL_TRANS_IDLE_TIMEOUT));
+ if (!ret) {
+ IWL_ERR(trans, "Timeout exiting D0i3\n");
+ ret = -ETIMEDOUT;
+ goto err;
+ }
+
+ return 0;
+ err:
+ clear_bit(STATUS_TRANS_IDLE, &trans->status);
+ iwl_trans_fw_error(trans);
+ return ret;
+ }
+
+ #ifdef CONFIG_IWLWIFI_PCIE_RTPM
+ static int iwl_pci_runtime_suspend(struct device *device)
+ {
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct iwl_trans *trans = pci_get_drvdata(pdev);
+ int ret;
+
+ IWL_DEBUG_RPM(trans, "entering runtime suspend\n");
+
+ if (test_bit(STATUS_DEVICE_ENABLED, &trans->status)) {
+ ret = iwl_pci_fw_enter_d0i3(trans);
+ if (ret < 0)
+ return ret;
+ }
+
+ trans->system_pm_mode = IWL_PLAT_PM_MODE_D0I3;
+
+ iwl_trans_d3_suspend(trans, false, false);
+
+ return 0;
+ }
+
+ static int iwl_pci_runtime_resume(struct device *device)
+ {
+ struct pci_dev *pdev = to_pci_dev(device);
+ struct iwl_trans *trans = pci_get_drvdata(pdev);
+ enum iwl_d3_status d3_status;
+
+ IWL_DEBUG_RPM(trans, "exiting runtime suspend (resume)\n");
+
+ iwl_trans_d3_resume(trans, &d3_status, false, false);
+
+ if (test_bit(STATUS_DEVICE_ENABLED, &trans->status))
+ return iwl_pci_fw_exit_d0i3(trans);
+
+ return 0;
+ }
+ #endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+
+ static const struct dev_pm_ops iwl_dev_pm_ops = {
+ SET_SYSTEM_SLEEP_PM_OPS(iwl_pci_suspend,
+ iwl_pci_resume)
+ #ifdef CONFIG_IWLWIFI_PCIE_RTPM
+ SET_RUNTIME_PM_OPS(iwl_pci_runtime_suspend,
+ iwl_pci_runtime_resume,
+ NULL)
+ #endif /* CONFIG_IWLWIFI_PCIE_RTPM */
+ };
#define IWL_PM_OPS (&iwl_dev_pm_ops)
- #else
+ #else /* CONFIG_PM_SLEEP */
#define IWL_PM_OPS NULL
- #endif
+ #endif /* CONFIG_PM_SLEEP */
static struct pci_driver iwl_pci_driver = {
.name = DRV_NAME,
* amount of bytes needed to move the data.
*/
#define ALIGN_SIZE(__skb, __header) \
- ( ((unsigned long)((__skb)->data + (__header))) & 3 )
+ (((unsigned long)((__skb)->data + (__header))) & 3)
/*
* Constants for extra TX headroom for alignment purposes.
#define SLOT_TIME 20
#define SHORT_SLOT_TIME 9
#define SIFS 10
- #define PIFS ( SIFS + SLOT_TIME )
- #define SHORT_PIFS ( SIFS + SHORT_SLOT_TIME )
- #define DIFS ( PIFS + SLOT_TIME )
- #define SHORT_DIFS ( SHORT_PIFS + SHORT_SLOT_TIME )
- #define EIFS ( SIFS + DIFS + \
- GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
- #define SHORT_EIFS ( SIFS + SHORT_DIFS + \
- GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10) )
+ #define PIFS (SIFS + SLOT_TIME)
+ #define SHORT_PIFS (SIFS + SHORT_SLOT_TIME)
+ #define DIFS (PIFS + SLOT_TIME)
+ #define SHORT_DIFS (SHORT_PIFS + SHORT_SLOT_TIME)
+ #define EIFS (SIFS + DIFS + \
+ GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10))
+ #define SHORT_EIFS (SIFS + SHORT_DIFS + \
+ GET_DURATION(IEEE80211_HEADER + ACK_SIZE, 10))
enum rt2x00_chip_intf {
RT2X00_CHIP_INTF_PCI,
CONFIG_POWERSAVING,
CONFIG_HT_DISABLED,
CONFIG_QOS_DISABLED,
+ CONFIG_MONITORING,
/*
* Mark we currently are sequentially reading TX_STA_FIFO register