584 lines
15 KiB
C
584 lines
15 KiB
C
|
// SPDX-License-Identifier: GPL-2.0-only
|
||
|
/*
|
||
|
* Copyright (c) 2021, MediaTek Inc.
|
||
|
* Copyright (c) 2021-2022, Intel Corporation.
|
||
|
*
|
||
|
* Authors:
|
||
|
* Amir Hanania <amir.hanania@intel.com>
|
||
|
* Haijun Liu <haijun.liu@mediatek.com>
|
||
|
* Moises Veleta <moises.veleta@intel.com>
|
||
|
* Ricardo Martinez <ricardo.martinez@linux.intel.com>
|
||
|
*
|
||
|
* Contributors:
|
||
|
* Chiranjeevi Rapolu <chiranjeevi.rapolu@intel.com>
|
||
|
* Eliot Lee <eliot.lee@intel.com>
|
||
|
* Sreehari Kancharla <sreehari.kancharla@intel.com>
|
||
|
*/
|
||
|
|
||
|
#include <linux/device.h>
|
||
|
#include <linux/gfp.h>
|
||
|
#include <linux/irqreturn.h>
|
||
|
#include <linux/kernel.h>
|
||
|
#include <linux/list.h>
|
||
|
#include <linux/string.h>
|
||
|
#include <linux/wait.h>
|
||
|
#include <linux/workqueue.h>
|
||
|
|
||
|
#include "t7xx_dpmaif.h"
|
||
|
#include "t7xx_hif_dpmaif.h"
|
||
|
#include "t7xx_hif_dpmaif_rx.h"
|
||
|
#include "t7xx_hif_dpmaif_tx.h"
|
||
|
#include "t7xx_pci.h"
|
||
|
#include "t7xx_pcie_mac.h"
|
||
|
#include "t7xx_state_monitor.h"
|
||
|
|
||
|
unsigned int t7xx_ring_buf_get_next_wr_idx(unsigned int buf_len, unsigned int buf_idx)
|
||
|
{
|
||
|
buf_idx++;
|
||
|
|
||
|
return buf_idx < buf_len ? buf_idx : 0;
|
||
|
}
|
||
|
|
||
|
unsigned int t7xx_ring_buf_rd_wr_count(unsigned int total_cnt, unsigned int rd_idx,
|
||
|
unsigned int wr_idx, enum dpmaif_rdwr rd_wr)
|
||
|
{
|
||
|
int pkt_cnt;
|
||
|
|
||
|
if (rd_wr == DPMAIF_READ)
|
||
|
pkt_cnt = wr_idx - rd_idx;
|
||
|
else
|
||
|
pkt_cnt = rd_idx - wr_idx - 1;
|
||
|
|
||
|
if (pkt_cnt < 0)
|
||
|
pkt_cnt += total_cnt;
|
||
|
|
||
|
return (unsigned int)pkt_cnt;
|
||
|
}
|
||
|
|
||
|
static void t7xx_dpmaif_enable_irq(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
struct dpmaif_isr_para *isr_para;
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < ARRAY_SIZE(dpmaif_ctrl->isr_para); i++) {
|
||
|
isr_para = &dpmaif_ctrl->isr_para[i];
|
||
|
t7xx_pcie_mac_set_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void t7xx_dpmaif_disable_irq(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
struct dpmaif_isr_para *isr_para;
|
||
|
int i;
|
||
|
|
||
|
for (i = 0; i < ARRAY_SIZE(dpmaif_ctrl->isr_para); i++) {
|
||
|
isr_para = &dpmaif_ctrl->isr_para[i];
|
||
|
t7xx_pcie_mac_clear_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void t7xx_dpmaif_irq_cb(struct dpmaif_isr_para *isr_para)
|
||
|
{
|
||
|
struct dpmaif_ctrl *dpmaif_ctrl = isr_para->dpmaif_ctrl;
|
||
|
struct dpmaif_hw_intr_st_para intr_status;
|
||
|
struct device *dev = dpmaif_ctrl->dev;
|
||
|
struct dpmaif_hw_info *hw_info;
|
||
|
int i;
|
||
|
|
||
|
memset(&intr_status, 0, sizeof(intr_status));
|
||
|
hw_info = &dpmaif_ctrl->hw_info;
|
||
|
|
||
|
if (t7xx_dpmaif_hw_get_intr_cnt(hw_info, &intr_status, isr_para->dlq_id) < 0) {
|
||
|
dev_err(dev, "Failed to get HW interrupt count\n");
|
||
|
return;
|
||
|
}
|
||
|
|
||
|
t7xx_pcie_mac_clear_int_status(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
|
||
|
|
||
|
for (i = 0; i < intr_status.intr_cnt; i++) {
|
||
|
switch (intr_status.intr_types[i]) {
|
||
|
case DPF_INTR_UL_DONE:
|
||
|
t7xx_dpmaif_irq_tx_done(dpmaif_ctrl, intr_status.intr_queues[i]);
|
||
|
break;
|
||
|
|
||
|
case DPF_INTR_UL_DRB_EMPTY:
|
||
|
case DPF_INTR_UL_MD_NOTREADY:
|
||
|
case DPF_INTR_UL_MD_PWR_NOTREADY:
|
||
|
/* No need to log an error for these */
|
||
|
break;
|
||
|
|
||
|
case DPF_INTR_DL_BATCNT_LEN_ERR:
|
||
|
dev_err_ratelimited(dev, "DL interrupt: packet BAT count length error\n");
|
||
|
t7xx_dpmaif_dl_unmask_batcnt_len_err_intr(hw_info);
|
||
|
break;
|
||
|
|
||
|
case DPF_INTR_DL_PITCNT_LEN_ERR:
|
||
|
dev_err_ratelimited(dev, "DL interrupt: PIT count length error\n");
|
||
|
t7xx_dpmaif_dl_unmask_pitcnt_len_err_intr(hw_info);
|
||
|
break;
|
||
|
|
||
|
case DPF_INTR_DL_Q0_PITCNT_LEN_ERR:
|
||
|
dev_err_ratelimited(dev, "DL interrupt: DLQ0 PIT count length error\n");
|
||
|
t7xx_dpmaif_dlq_unmask_pitcnt_len_err_intr(hw_info, DPF_RX_QNO_DFT);
|
||
|
break;
|
||
|
|
||
|
case DPF_INTR_DL_Q1_PITCNT_LEN_ERR:
|
||
|
dev_err_ratelimited(dev, "DL interrupt: DLQ1 PIT count length error\n");
|
||
|
t7xx_dpmaif_dlq_unmask_pitcnt_len_err_intr(hw_info, DPF_RX_QNO1);
|
||
|
break;
|
||
|
|
||
|
case DPF_INTR_DL_DONE:
|
||
|
case DPF_INTR_DL_Q0_DONE:
|
||
|
case DPF_INTR_DL_Q1_DONE:
|
||
|
t7xx_dpmaif_irq_rx_done(dpmaif_ctrl, intr_status.intr_queues[i]);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
dev_err_ratelimited(dev, "DL interrupt error: unknown type : %d\n",
|
||
|
intr_status.intr_types[i]);
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static irqreturn_t t7xx_dpmaif_isr_handler(int irq, void *data)
|
||
|
{
|
||
|
struct dpmaif_isr_para *isr_para = data;
|
||
|
struct dpmaif_ctrl *dpmaif_ctrl;
|
||
|
|
||
|
dpmaif_ctrl = isr_para->dpmaif_ctrl;
|
||
|
if (dpmaif_ctrl->state != DPMAIF_STATE_PWRON) {
|
||
|
dev_err(dpmaif_ctrl->dev, "Interrupt received before initializing DPMAIF\n");
|
||
|
return IRQ_HANDLED;
|
||
|
}
|
||
|
|
||
|
t7xx_pcie_mac_clear_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
|
||
|
|
||
|
return IRQ_WAKE_THREAD;
|
||
|
}
|
||
|
|
||
|
static irqreturn_t t7xx_dpmaif_isr_thread(int irq, void *data)
|
||
|
{
|
||
|
struct dpmaif_isr_para *isr_para = data;
|
||
|
struct dpmaif_ctrl *dpmaif_ctrl = isr_para->dpmaif_ctrl;
|
||
|
|
||
|
t7xx_dpmaif_irq_cb(isr_para);
|
||
|
t7xx_pcie_mac_set_int(dpmaif_ctrl->t7xx_dev, isr_para->pcie_int);
|
||
|
return IRQ_HANDLED;
|
||
|
}
|
||
|
|
||
|
static void t7xx_dpmaif_isr_parameter_init(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
struct dpmaif_isr_para *isr_para;
|
||
|
unsigned char i;
|
||
|
|
||
|
dpmaif_ctrl->rxq_int_mapping[DPF_RX_QNO0] = DPMAIF_INT;
|
||
|
dpmaif_ctrl->rxq_int_mapping[DPF_RX_QNO1] = DPMAIF2_INT;
|
||
|
|
||
|
for (i = 0; i < DPMAIF_RXQ_NUM; i++) {
|
||
|
isr_para = &dpmaif_ctrl->isr_para[i];
|
||
|
isr_para->dpmaif_ctrl = dpmaif_ctrl;
|
||
|
isr_para->dlq_id = i;
|
||
|
isr_para->pcie_int = dpmaif_ctrl->rxq_int_mapping[i];
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static void t7xx_dpmaif_register_pcie_irq(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
struct t7xx_pci_dev *t7xx_dev = dpmaif_ctrl->t7xx_dev;
|
||
|
struct dpmaif_isr_para *isr_para;
|
||
|
enum t7xx_int int_type;
|
||
|
int i;
|
||
|
|
||
|
t7xx_dpmaif_isr_parameter_init(dpmaif_ctrl);
|
||
|
|
||
|
for (i = 0; i < DPMAIF_RXQ_NUM; i++) {
|
||
|
isr_para = &dpmaif_ctrl->isr_para[i];
|
||
|
int_type = isr_para->pcie_int;
|
||
|
t7xx_pcie_mac_clear_int(t7xx_dev, int_type);
|
||
|
|
||
|
t7xx_dev->intr_handler[int_type] = t7xx_dpmaif_isr_handler;
|
||
|
t7xx_dev->intr_thread[int_type] = t7xx_dpmaif_isr_thread;
|
||
|
t7xx_dev->callback_param[int_type] = isr_para;
|
||
|
|
||
|
t7xx_pcie_mac_clear_int_status(t7xx_dev, int_type);
|
||
|
t7xx_pcie_mac_set_int(t7xx_dev, int_type);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int t7xx_dpmaif_rxtx_sw_allocs(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
struct dpmaif_rx_queue *rx_q;
|
||
|
struct dpmaif_tx_queue *tx_q;
|
||
|
int ret, rx_idx, tx_idx, i;
|
||
|
|
||
|
ret = t7xx_dpmaif_bat_alloc(dpmaif_ctrl, &dpmaif_ctrl->bat_req, BAT_TYPE_NORMAL);
|
||
|
if (ret) {
|
||
|
dev_err(dpmaif_ctrl->dev, "Failed to allocate normal BAT table: %d\n", ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
ret = t7xx_dpmaif_bat_alloc(dpmaif_ctrl, &dpmaif_ctrl->bat_frag, BAT_TYPE_FRAG);
|
||
|
if (ret) {
|
||
|
dev_err(dpmaif_ctrl->dev, "Failed to allocate frag BAT table: %d\n", ret);
|
||
|
goto err_free_normal_bat;
|
||
|
}
|
||
|
|
||
|
for (rx_idx = 0; rx_idx < DPMAIF_RXQ_NUM; rx_idx++) {
|
||
|
rx_q = &dpmaif_ctrl->rxq[rx_idx];
|
||
|
rx_q->index = rx_idx;
|
||
|
rx_q->dpmaif_ctrl = dpmaif_ctrl;
|
||
|
ret = t7xx_dpmaif_rxq_init(rx_q);
|
||
|
if (ret)
|
||
|
goto err_free_rxq;
|
||
|
}
|
||
|
|
||
|
for (tx_idx = 0; tx_idx < DPMAIF_TXQ_NUM; tx_idx++) {
|
||
|
tx_q = &dpmaif_ctrl->txq[tx_idx];
|
||
|
tx_q->index = tx_idx;
|
||
|
tx_q->dpmaif_ctrl = dpmaif_ctrl;
|
||
|
ret = t7xx_dpmaif_txq_init(tx_q);
|
||
|
if (ret)
|
||
|
goto err_free_txq;
|
||
|
}
|
||
|
|
||
|
ret = t7xx_dpmaif_tx_thread_init(dpmaif_ctrl);
|
||
|
if (ret) {
|
||
|
dev_err(dpmaif_ctrl->dev, "Failed to start TX thread\n");
|
||
|
goto err_free_txq;
|
||
|
}
|
||
|
|
||
|
ret = t7xx_dpmaif_bat_rel_wq_alloc(dpmaif_ctrl);
|
||
|
if (ret)
|
||
|
goto err_thread_rel;
|
||
|
|
||
|
return 0;
|
||
|
|
||
|
err_thread_rel:
|
||
|
t7xx_dpmaif_tx_thread_rel(dpmaif_ctrl);
|
||
|
|
||
|
err_free_txq:
|
||
|
for (i = 0; i < tx_idx; i++) {
|
||
|
tx_q = &dpmaif_ctrl->txq[i];
|
||
|
t7xx_dpmaif_txq_free(tx_q);
|
||
|
}
|
||
|
|
||
|
err_free_rxq:
|
||
|
for (i = 0; i < rx_idx; i++) {
|
||
|
rx_q = &dpmaif_ctrl->rxq[i];
|
||
|
t7xx_dpmaif_rxq_free(rx_q);
|
||
|
}
|
||
|
|
||
|
t7xx_dpmaif_bat_free(dpmaif_ctrl, &dpmaif_ctrl->bat_frag);
|
||
|
|
||
|
err_free_normal_bat:
|
||
|
t7xx_dpmaif_bat_free(dpmaif_ctrl, &dpmaif_ctrl->bat_req);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static void t7xx_dpmaif_sw_release(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
struct dpmaif_rx_queue *rx_q;
|
||
|
struct dpmaif_tx_queue *tx_q;
|
||
|
int i;
|
||
|
|
||
|
t7xx_dpmaif_tx_thread_rel(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_bat_wq_rel(dpmaif_ctrl);
|
||
|
|
||
|
for (i = 0; i < DPMAIF_TXQ_NUM; i++) {
|
||
|
tx_q = &dpmaif_ctrl->txq[i];
|
||
|
t7xx_dpmaif_txq_free(tx_q);
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < DPMAIF_RXQ_NUM; i++) {
|
||
|
rx_q = &dpmaif_ctrl->rxq[i];
|
||
|
t7xx_dpmaif_rxq_free(rx_q);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int t7xx_dpmaif_start(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
struct dpmaif_hw_info *hw_info = &dpmaif_ctrl->hw_info;
|
||
|
struct dpmaif_hw_params hw_init_para;
|
||
|
struct dpmaif_rx_queue *rxq;
|
||
|
struct dpmaif_tx_queue *txq;
|
||
|
unsigned int buf_cnt;
|
||
|
int i, ret = 0;
|
||
|
|
||
|
if (dpmaif_ctrl->state == DPMAIF_STATE_PWRON)
|
||
|
return -EFAULT;
|
||
|
|
||
|
memset(&hw_init_para, 0, sizeof(hw_init_para));
|
||
|
|
||
|
for (i = 0; i < DPMAIF_RXQ_NUM; i++) {
|
||
|
rxq = &dpmaif_ctrl->rxq[i];
|
||
|
rxq->que_started = true;
|
||
|
rxq->index = i;
|
||
|
rxq->budget = rxq->bat_req->bat_size_cnt - 1;
|
||
|
|
||
|
hw_init_para.pkt_bat_base_addr[i] = rxq->bat_req->bat_bus_addr;
|
||
|
hw_init_para.pkt_bat_size_cnt[i] = rxq->bat_req->bat_size_cnt;
|
||
|
hw_init_para.pit_base_addr[i] = rxq->pit_bus_addr;
|
||
|
hw_init_para.pit_size_cnt[i] = rxq->pit_size_cnt;
|
||
|
hw_init_para.frg_bat_base_addr[i] = rxq->bat_frag->bat_bus_addr;
|
||
|
hw_init_para.frg_bat_size_cnt[i] = rxq->bat_frag->bat_size_cnt;
|
||
|
}
|
||
|
|
||
|
bitmap_zero(dpmaif_ctrl->bat_req.bat_bitmap, dpmaif_ctrl->bat_req.bat_size_cnt);
|
||
|
buf_cnt = dpmaif_ctrl->bat_req.bat_size_cnt - 1;
|
||
|
ret = t7xx_dpmaif_rx_buf_alloc(dpmaif_ctrl, &dpmaif_ctrl->bat_req, 0, buf_cnt, true);
|
||
|
if (ret) {
|
||
|
dev_err(dpmaif_ctrl->dev, "Failed to allocate RX buffer: %d\n", ret);
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
buf_cnt = dpmaif_ctrl->bat_frag.bat_size_cnt - 1;
|
||
|
ret = t7xx_dpmaif_rx_frag_alloc(dpmaif_ctrl, &dpmaif_ctrl->bat_frag, buf_cnt, true);
|
||
|
if (ret) {
|
||
|
dev_err(dpmaif_ctrl->dev, "Failed to allocate frag RX buffer: %d\n", ret);
|
||
|
goto err_free_normal_bat;
|
||
|
}
|
||
|
|
||
|
for (i = 0; i < DPMAIF_TXQ_NUM; i++) {
|
||
|
txq = &dpmaif_ctrl->txq[i];
|
||
|
txq->que_started = true;
|
||
|
|
||
|
hw_init_para.drb_base_addr[i] = txq->drb_bus_addr;
|
||
|
hw_init_para.drb_size_cnt[i] = txq->drb_size_cnt;
|
||
|
}
|
||
|
|
||
|
ret = t7xx_dpmaif_hw_init(hw_info, &hw_init_para);
|
||
|
if (ret) {
|
||
|
dev_err(dpmaif_ctrl->dev, "Failed to initialize DPMAIF HW: %d\n", ret);
|
||
|
goto err_free_frag_bat;
|
||
|
}
|
||
|
|
||
|
ret = t7xx_dpmaif_dl_snd_hw_bat_cnt(hw_info, rxq->bat_req->bat_size_cnt - 1);
|
||
|
if (ret)
|
||
|
goto err_free_frag_bat;
|
||
|
|
||
|
ret = t7xx_dpmaif_dl_snd_hw_frg_cnt(hw_info, rxq->bat_frag->bat_size_cnt - 1);
|
||
|
if (ret)
|
||
|
goto err_free_frag_bat;
|
||
|
|
||
|
t7xx_dpmaif_ul_clr_all_intr(hw_info);
|
||
|
t7xx_dpmaif_dl_clr_all_intr(hw_info);
|
||
|
dpmaif_ctrl->state = DPMAIF_STATE_PWRON;
|
||
|
t7xx_dpmaif_enable_irq(dpmaif_ctrl);
|
||
|
wake_up(&dpmaif_ctrl->tx_wq);
|
||
|
return 0;
|
||
|
|
||
|
err_free_frag_bat:
|
||
|
t7xx_dpmaif_bat_free(rxq->dpmaif_ctrl, rxq->bat_frag);
|
||
|
|
||
|
err_free_normal_bat:
|
||
|
t7xx_dpmaif_bat_free(rxq->dpmaif_ctrl, rxq->bat_req);
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static void t7xx_dpmaif_stop_sw(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
t7xx_dpmaif_tx_stop(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_rx_stop(dpmaif_ctrl);
|
||
|
}
|
||
|
|
||
|
static void t7xx_dpmaif_stop_hw(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
t7xx_dpmaif_hw_stop_all_txq(&dpmaif_ctrl->hw_info);
|
||
|
t7xx_dpmaif_hw_stop_all_rxq(&dpmaif_ctrl->hw_info);
|
||
|
}
|
||
|
|
||
|
static int t7xx_dpmaif_stop(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
if (!dpmaif_ctrl->dpmaif_sw_init_done) {
|
||
|
dev_err(dpmaif_ctrl->dev, "dpmaif SW init fail\n");
|
||
|
return -EFAULT;
|
||
|
}
|
||
|
|
||
|
if (dpmaif_ctrl->state == DPMAIF_STATE_PWROFF)
|
||
|
return -EFAULT;
|
||
|
|
||
|
t7xx_dpmaif_disable_irq(dpmaif_ctrl);
|
||
|
dpmaif_ctrl->state = DPMAIF_STATE_PWROFF;
|
||
|
t7xx_dpmaif_stop_sw(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_tx_clear(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_rx_clear(dpmaif_ctrl);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int t7xx_dpmaif_suspend(struct t7xx_pci_dev *t7xx_dev, void *param)
|
||
|
{
|
||
|
struct dpmaif_ctrl *dpmaif_ctrl = param;
|
||
|
|
||
|
t7xx_dpmaif_tx_stop(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_hw_stop_all_txq(&dpmaif_ctrl->hw_info);
|
||
|
t7xx_dpmaif_hw_stop_all_rxq(&dpmaif_ctrl->hw_info);
|
||
|
t7xx_dpmaif_disable_irq(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_rx_stop(dpmaif_ctrl);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static void t7xx_dpmaif_unmask_dlq_intr(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
int qno;
|
||
|
|
||
|
for (qno = 0; qno < DPMAIF_RXQ_NUM; qno++)
|
||
|
t7xx_dpmaif_dlq_unmask_rx_done(&dpmaif_ctrl->hw_info, qno);
|
||
|
}
|
||
|
|
||
|
static void t7xx_dpmaif_start_txrx_qs(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
struct dpmaif_rx_queue *rxq;
|
||
|
struct dpmaif_tx_queue *txq;
|
||
|
unsigned int que_cnt;
|
||
|
|
||
|
for (que_cnt = 0; que_cnt < DPMAIF_TXQ_NUM; que_cnt++) {
|
||
|
txq = &dpmaif_ctrl->txq[que_cnt];
|
||
|
txq->que_started = true;
|
||
|
}
|
||
|
|
||
|
for (que_cnt = 0; que_cnt < DPMAIF_RXQ_NUM; que_cnt++) {
|
||
|
rxq = &dpmaif_ctrl->rxq[que_cnt];
|
||
|
rxq->que_started = true;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
static int t7xx_dpmaif_resume(struct t7xx_pci_dev *t7xx_dev, void *param)
|
||
|
{
|
||
|
struct dpmaif_ctrl *dpmaif_ctrl = param;
|
||
|
|
||
|
if (!dpmaif_ctrl)
|
||
|
return 0;
|
||
|
|
||
|
t7xx_dpmaif_start_txrx_qs(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_enable_irq(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_unmask_dlq_intr(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_start_hw(&dpmaif_ctrl->hw_info);
|
||
|
wake_up(&dpmaif_ctrl->tx_wq);
|
||
|
return 0;
|
||
|
}
|
||
|
|
||
|
static int t7xx_dpmaif_pm_entity_init(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
struct md_pm_entity *dpmaif_pm_entity = &dpmaif_ctrl->dpmaif_pm_entity;
|
||
|
int ret;
|
||
|
|
||
|
INIT_LIST_HEAD(&dpmaif_pm_entity->entity);
|
||
|
dpmaif_pm_entity->suspend = &t7xx_dpmaif_suspend;
|
||
|
dpmaif_pm_entity->suspend_late = NULL;
|
||
|
dpmaif_pm_entity->resume_early = NULL;
|
||
|
dpmaif_pm_entity->resume = &t7xx_dpmaif_resume;
|
||
|
dpmaif_pm_entity->id = PM_ENTITY_ID_DATA;
|
||
|
dpmaif_pm_entity->entity_param = dpmaif_ctrl;
|
||
|
|
||
|
ret = t7xx_pci_pm_entity_register(dpmaif_ctrl->t7xx_dev, dpmaif_pm_entity);
|
||
|
if (ret)
|
||
|
dev_err(dpmaif_ctrl->dev, "dpmaif register pm_entity fail\n");
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
static int t7xx_dpmaif_pm_entity_release(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
struct md_pm_entity *dpmaif_pm_entity = &dpmaif_ctrl->dpmaif_pm_entity;
|
||
|
int ret;
|
||
|
|
||
|
ret = t7xx_pci_pm_entity_unregister(dpmaif_ctrl->t7xx_dev, dpmaif_pm_entity);
|
||
|
if (ret < 0)
|
||
|
dev_err(dpmaif_ctrl->dev, "dpmaif register pm_entity fail\n");
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
int t7xx_dpmaif_md_state_callback(struct dpmaif_ctrl *dpmaif_ctrl, enum md_state state)
|
||
|
{
|
||
|
int ret = 0;
|
||
|
|
||
|
switch (state) {
|
||
|
case MD_STATE_WAITING_FOR_HS1:
|
||
|
ret = t7xx_dpmaif_start(dpmaif_ctrl);
|
||
|
break;
|
||
|
|
||
|
case MD_STATE_EXCEPTION:
|
||
|
ret = t7xx_dpmaif_stop(dpmaif_ctrl);
|
||
|
break;
|
||
|
|
||
|
case MD_STATE_STOPPED:
|
||
|
ret = t7xx_dpmaif_stop(dpmaif_ctrl);
|
||
|
break;
|
||
|
|
||
|
case MD_STATE_WAITING_TO_STOP:
|
||
|
t7xx_dpmaif_stop_hw(dpmaif_ctrl);
|
||
|
break;
|
||
|
|
||
|
default:
|
||
|
break;
|
||
|
}
|
||
|
|
||
|
return ret;
|
||
|
}
|
||
|
|
||
|
/**
|
||
|
* t7xx_dpmaif_hif_init() - Initialize data path.
|
||
|
* @t7xx_dev: MTK context structure.
|
||
|
* @callbacks: Callbacks implemented by the network layer to handle RX skb and
|
||
|
* event notifications.
|
||
|
*
|
||
|
* Allocate and initialize datapath control block.
|
||
|
* Register datapath ISR, TX and RX resources.
|
||
|
*
|
||
|
* Return:
|
||
|
* * dpmaif_ctrl pointer - Pointer to DPMAIF context structure.
|
||
|
* * NULL - In case of error.
|
||
|
*/
|
||
|
struct dpmaif_ctrl *t7xx_dpmaif_hif_init(struct t7xx_pci_dev *t7xx_dev,
|
||
|
struct dpmaif_callbacks *callbacks)
|
||
|
{
|
||
|
struct device *dev = &t7xx_dev->pdev->dev;
|
||
|
struct dpmaif_ctrl *dpmaif_ctrl;
|
||
|
int ret;
|
||
|
|
||
|
if (!callbacks)
|
||
|
return NULL;
|
||
|
|
||
|
dpmaif_ctrl = devm_kzalloc(dev, sizeof(*dpmaif_ctrl), GFP_KERNEL);
|
||
|
if (!dpmaif_ctrl)
|
||
|
return NULL;
|
||
|
|
||
|
dpmaif_ctrl->t7xx_dev = t7xx_dev;
|
||
|
dpmaif_ctrl->callbacks = callbacks;
|
||
|
dpmaif_ctrl->dev = dev;
|
||
|
dpmaif_ctrl->dpmaif_sw_init_done = false;
|
||
|
dpmaif_ctrl->hw_info.dev = dev;
|
||
|
dpmaif_ctrl->hw_info.pcie_base = t7xx_dev->base_addr.pcie_ext_reg_base -
|
||
|
t7xx_dev->base_addr.pcie_dev_reg_trsl_addr;
|
||
|
|
||
|
ret = t7xx_dpmaif_pm_entity_init(dpmaif_ctrl);
|
||
|
if (ret)
|
||
|
return NULL;
|
||
|
|
||
|
t7xx_dpmaif_register_pcie_irq(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_disable_irq(dpmaif_ctrl);
|
||
|
|
||
|
ret = t7xx_dpmaif_rxtx_sw_allocs(dpmaif_ctrl);
|
||
|
if (ret) {
|
||
|
t7xx_dpmaif_pm_entity_release(dpmaif_ctrl);
|
||
|
dev_err(dev, "Failed to allocate RX/TX SW resources: %d\n", ret);
|
||
|
return NULL;
|
||
|
}
|
||
|
|
||
|
dpmaif_ctrl->dpmaif_sw_init_done = true;
|
||
|
return dpmaif_ctrl;
|
||
|
}
|
||
|
|
||
|
void t7xx_dpmaif_hif_exit(struct dpmaif_ctrl *dpmaif_ctrl)
|
||
|
{
|
||
|
if (dpmaif_ctrl->dpmaif_sw_init_done) {
|
||
|
t7xx_dpmaif_stop(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_pm_entity_release(dpmaif_ctrl);
|
||
|
t7xx_dpmaif_sw_release(dpmaif_ctrl);
|
||
|
dpmaif_ctrl->dpmaif_sw_init_done = false;
|
||
|
}
|
||
|
}
|