// SPDX-License-Identifier: BSD-3-Clause-Clear /* * Copyright (c) 2019-2021 The Linux Foundation. All rights reserved. * Copyright (c) 2021-2024 Qualcomm Innovation Center, Inc. All rights reserved. * Copyright (c) Qualcomm Technologies, Inc. and/or its subsidiaries.
*/
void ath11k_pcic_write32(struct ath11k_base *ab, u32 offset, u32 value)
{ int ret = 0; bool wakeup_required;
/* for offset beyond BAR + 4K - 32, may * need to wakeup the device to access.
*/
wakeup_required = test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF; if (wakeup_required && ab->pci.ops->wakeup)
ret = ab->pci.ops->wakeup(ab);
__ath11k_pcic_write32(ab, offset, value);
if (wakeup_required && !ret && ab->pci.ops->release)
ab->pci.ops->release(ab);
}
EXPORT_SYMBOL(ath11k_pcic_write32);
if (offset < ATH11K_PCI_WINDOW_START)
val = ioread32(ab->mem + offset); else
val = ab->pci.ops->window_read32(ab, offset);
return val;
}
u32 ath11k_pcic_read32(struct ath11k_base *ab, u32 offset)
{ int ret = 0;
u32 val; bool wakeup_required;
/* for offset beyond BAR + 4K - 32, may * need to wakeup the device to access.
*/
wakeup_required = test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
offset >= ATH11K_PCI_ACCESS_ALWAYS_OFF; if (wakeup_required && ab->pci.ops->wakeup)
ret = ab->pci.ops->wakeup(ab);
val = __ath11k_pcic_read32(ab, offset);
if (wakeup_required && !ret && ab->pci.ops->release)
ab->pci.ops->release(ab);
return val;
}
EXPORT_SYMBOL(ath11k_pcic_read32);
int ath11k_pcic_read(struct ath11k_base *ab, void *buf, u32 start, u32 end)
{ int ret = 0; bool wakeup_required;
u32 *data = buf;
u32 i;
/* for offset beyond BAR + 4K - 32, may * need to wakeup the device to access.
*/
wakeup_required = test_bit(ATH11K_FLAG_DEVICE_INIT_DONE, &ab->dev_flags) &&
end >= ATH11K_PCI_ACCESS_ALWAYS_OFF; if (wakeup_required && ab->pci.ops->wakeup) {
ret = ab->pci.ops->wakeup(ab); if (ret) {
ath11k_warn(ab, "wakeup failed, data may be invalid: %d",
ret); /* Even though wakeup() failed, continue processing rather * than returning because some parts of the data may still * be valid and useful in some cases, e.g. could give us * some clues on firmware crash. * Mislead due to invalid data could be avoided because we * are aware of the wakeup failure.
*/
}
}
for (i = start; i < end + 1; i += 4)
*data++ = __ath11k_pcic_read32(ab, i);
if (wakeup_required && ab->pci.ops->release)
ab->pci.ops->release(ab);
/* In case of one MSI vector, we handle irq enable/disable in a * uniform way since we only have one irq
*/ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) return;
/* In case of one MSI vector, we handle irq enable/disable in a * uniform way since we only have one irq
*/ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) return;
for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue;
ath11k_pcic_ce_irq_disable(ab, i);
}
}
staticvoid ath11k_pcic_sync_ce_irqs(struct ath11k_base *ab)
{ int i; int irq_idx;
for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue;
/* In case of one MSI vector, we handle irq enable/disable * in a uniform way since we only have one irq
*/ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) return;
for (i = 0; i < irq_grp->num_irq; i++)
disable_irq_nosync(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
}
staticvoid __ath11k_pcic_ext_irq_disable(struct ath11k_base *ab)
{ int i;
/* In case of one MSI vector, we handle irq enable/disable in a * uniform way since we only have one irq
*/ if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags)) return;
for (i = 0; i < irq_grp->num_irq; i++)
enable_irq(irq_grp->ab->irq_num[irq_grp->irqs[i]]);
}
void ath11k_pcic_ext_irq_enable(struct ath11k_base *ab)
{ int i;
for (i = 0; i < ATH11K_EXT_IRQ_GRP_NUM_MAX; i++) { struct ath11k_ext_irq_grp *irq_grp = &ab->ext_irq_grp[i];
if (!irq_grp->napi_enabled) {
napi_enable(&irq_grp->napi);
irq_grp->napi_enabled = true;
}
ath11k_pcic_ext_grp_enable(irq_grp);
}
for (j = 0; j < irq_grp->num_irq; j++) { int irq_idx = irq_grp->irqs[j]; int vector = (i % num_vectors) + base_vector; int irq = ath11k_pcic_get_msi_irq(ab, vector);
if (irq < 0) {
ret = irq; goto fail_irq;
}
ab->irq_num[irq_idx] = irq;
ath11k_dbg(ab, ATH11K_DBG_PCI, "irq %d group %d\n", irq, i);
irq_set_status_flags(irq, IRQ_DISABLE_UNLAZY);
ret = request_irq(irq, ath11k_pcic_ext_interrupt_handler,
irq_flags, "DP_EXT_IRQ", irq_grp); if (ret) {
ath11k_err(ab, "failed request irq %d: %d\n",
vector, ret); for (n = 0; n <= i; n++) {
irq_grp = &ab->ext_irq_grp[n];
free_netdev(irq_grp->napi_ndev);
} return ret;
}
}
ath11k_pcic_ext_grp_disable(irq_grp);
}
return 0;
fail_irq: /* i ->napi_ndev was properly allocated. Free it also */
i += 1;
fail_allocate: for (n = 0; n < i; n++) {
irq_grp = &ab->ext_irq_grp[n];
free_netdev(irq_grp->napi_ndev);
} return ret;
}
int ath11k_pcic_config_irq(struct ath11k_base *ab)
{ struct ath11k_ce_pipe *ce_pipe;
u32 msi_data_start;
u32 msi_data_count, msi_data_idx;
u32 msi_irq_start; unsignedint msi_data; int irq, i, ret, irq_idx; unsignedlong irq_flags;
ret = ath11k_pcic_get_user_msi_assignment(ab, "CE", &msi_data_count,
&msi_data_start, &msi_irq_start); if (ret) return ret;
irq_flags = IRQF_SHARED; if (!test_bit(ATH11K_FLAG_MULTI_MSI_VECTORS, &ab->dev_flags))
irq_flags |= IRQF_NOBALANCING;
/* Configure CE irqs */ for (i = 0, msi_data_idx = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue;
for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue;
ath11k_pcic_ce_irq_enable(ab, i);
}
}
EXPORT_SYMBOL(ath11k_pcic_ce_irqs_enable);
staticvoid ath11k_pcic_kill_tasklets(struct ath11k_base *ab)
{ int i;
for (i = 0; i < ab->hw_params.ce_count; i++) { struct ath11k_ce_pipe *ce_pipe = &ab->ce.ce_pipe[i];
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR) continue;
void ath11k_pci_enable_ce_irqs_except_wake_irq(struct ath11k_base *ab)
{ int i;
for (i = 0; i < ab->hw_params.ce_count; i++) { if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR ||
i == ATH11K_PCI_CE_WAKE_IRQ) continue;
ath11k_pcic_ce_irq_enable(ab, i);
}
}
EXPORT_SYMBOL(ath11k_pci_enable_ce_irqs_except_wake_irq);
void ath11k_pci_disable_ce_irqs_except_wake_irq(struct ath11k_base *ab)
{ int i; int irq_idx; struct ath11k_ce_pipe *ce_pipe;
for (i = 0; i < ab->hw_params.ce_count; i++) {
ce_pipe = &ab->ce.ce_pipe[i];
irq_idx = ATH11K_PCI_IRQ_CE0_OFFSET + i;
if (ath11k_ce_get_attr_flags(ab, i) & CE_ATTR_DIS_INTR ||
i == ATH11K_PCI_CE_WAKE_IRQ) continue;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.