// SPDX-License-Identifier: GPL-2.0+
/* Copyright (c) 2018 Quantenna Communications */
#include <linux/kernel.h>
#include <linux/firmware.h>
#include <linux/pci.h>
#include <linux/vmalloc.h>
#include <linux/delay.h>
#include <linux/interrupt.h>
#include <linux/sched.h>
#include <linux/completion.h>
#include <linux/crc32.h>
#include <linux/spinlock.h>
#include <linux/circ_buf.h>
#include <linux/log2.h>
#include "pcie_priv.h"
#include "pearl_pcie_regs.h"
#include "pearl_pcie_ipc.h"
#include "qtn_hw_ids.h"
#include "core.h"
#include "bus.h"
#include "shm_ipc.h"
#include "debug.h"
#define PEARL_TX_BD_SIZE_DEFAULT 32
#define PEARL_RX_BD_SIZE_DEFAULT 256
struct qtnf_pearl_bda {
__le16 bda_len;
__le16 bda_version;
__le32 bda_pci_endian;
__le32 bda_ep_state;
__le32 bda_rc_state;
__le32 bda_dma_mask;
__le32 bda_msi_addr;
__le32 bda_flashsz;
u8 bda_boardname[PCIE_BDA_NAMELEN];
__le32 bda_rc_msi_enabled;
u8 bda_hhbm_list[PCIE_HHBM_MAX_SIZE];
__le32 bda_dsbw_start_index;
__le32 bda_dsbw_end_index;
__le32 bda_dsbw_total_bytes;
__le32 bda_rc_tx_bd_base;
__le32 bda_rc_tx_bd_num;
u8 bda_pcie_mac[QTN_ENET_ADDR_LENGTH];
struct qtnf_shm_ipc_region bda_shm_reg1 __aligned(4096); /* host TX */
struct qtnf_shm_ipc_region bda_shm_reg2 __aligned(4096); /* host RX */
} __packed;
struct qtnf_pearl_tx_bd {
__le32 addr;
__le32 addr_h;
__le32 info;
__le32 info_h;
} __packed;
struct qtnf_pearl_rx_bd {
__le32 addr;
__le32 addr_h;
__le32 info;
__le32 info_h;
__le32 next_ptr;
__le32 next_ptr_h;
} __packed;
struct qtnf_pearl_fw_hdr {
u8 boardflg[8];
__le32 fwsize;
__le32 seqnum;
__le32 type;
__le32 pktlen;
__le32 crc;
} __packed;
struct qtnf_pcie_pearl_state {
struct qtnf_pcie_bus_priv base;
/* lock for irq configuration changes */
spinlock_t irq_lock;
struct qtnf_pearl_bda __iomem *bda;
void __iomem *pcie_reg_base;
struct qtnf_pearl_tx_bd *tx_bd_vbase;
dma_addr_t tx_bd_pbase;
struct qtnf_pearl_rx_bd *rx_bd_vbase;
dma_addr_t rx_bd_pbase;
dma_addr_t bd_table_paddr;
void *bd_table_vaddr;
u32 bd_table_len;
u32 pcie_irq_mask;
u32 pcie_irq_rx_count;
u32 pcie_irq_tx_count;
u32 pcie_irq_uf_count;
};
static inline void qtnf_init_hdp_irqs(struct qtnf_pcie_pearl_state *ps)
{
unsigned long flags;
spin_lock_irqsave(&ps->irq_lock, flags);
ps->pcie_irq_mask = (PCIE_HDP_INT_RX_BITS | PCIE_HDP_INT_TX_BITS);
spin_unlock_irqrestore(&ps->irq_lock, flags);
}
static inline void qtnf_enable_hdp_irqs(struct qtnf_pcie_pearl_state *ps)
{
unsigned long flags;
spin_lock_irqsave(&ps->irq_lock, flags);
writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base));
spin_unlock_irqrestore(&ps->irq_lock, flags);
}
static inline void qtnf_disable_hdp_irqs(struct qtnf_pcie_pearl_state *ps)
{
unsigned long flags;
spin_lock_irqsave(&ps->irq_lock, flags);
writel(0x0, PCIE_HDP_INT_EN(ps->pcie_reg_base));
spin_unlock_irqrestore(&ps->irq_lock, flags);
}
static inline void qtnf_en_rxdone_irq(struct qtnf_pcie_pearl_state *ps)
{
unsigned long flags;
spin_lock_irqsave(&ps->irq_lock, flags);
ps->pcie_irq_mask |= PCIE_HDP_INT_RX_BITS;
writel(ps->pcie_irq_mask, PCIE_HDP_INT_EN(ps->pcie_reg_base));
spin_unlock_irqrestore(&ps->irq_lock, flags);
}
static inline void qtnf_dis_rxdone_irq(struct qtnf_pcie_pearl_state *ps)
{
unsigned long flags;
spin_lock_irqsave(&ps->irq_lock, flags);
ps->pcie_irq_mask &= ~PCIE_HDP_INT_RX_BITS;
write