static void qtnf_pcie_remove(struct pci_dev *dev) { struct qtnf_pcie_bus_priv *priv; struct qtnf_bus *bus; bus = pci_get_drvdata(dev); if (!bus) return; priv = get_bus_priv(bus); cancel_work_sync(&bus->fw_work); if (bus->fw_state == QTNF_FW_STATE_ACTIVE || bus->fw_state == QTNF_FW_STATE_EP_DEAD) qtnf_core_detach(bus); netif_napi_del(&bus->mux_napi); flush_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue); tasklet_kill(&priv->reclaim_tq); qtnf_pcie_free_shm_ipc(priv); qtnf_debugfs_remove(bus); priv->remove_cb(bus); pci_set_drvdata(priv->pdev, NULL); }
static void qtnf_pcie_data_rx_start(struct qtnf_bus *bus) { struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); qtnf_enable_hdp_irqs(priv); napi_enable(&bus->mux_napi); }
void qtnf_pcie_fw_boot_done(struct qtnf_bus *bus, bool boot_success) { struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); struct pci_dev *pdev = priv->pdev; int ret; if (boot_success) { bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; ret = qtnf_core_attach(bus); if (ret) { pr_err("failed to attach core\n"); boot_success = false; } } if (boot_success) { qtnf_debugfs_init(bus, DRV_NAME); qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); } else { bus->fw_state = QTNF_FW_STATE_DETACHED; } put_device(&pdev->dev); }
static void qtnf_pcie_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev) { struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); tasklet_hi_schedule(&priv->reclaim_tq); }
static void qtnf_pcie_remove(struct pci_dev *pdev) { struct qtnf_pcie_bus_priv *priv; struct qtnf_bus *bus; bus = pci_get_drvdata(pdev); if (!bus) return; wait_for_completion(&bus->firmware_init_complete); if (bus->fw_state == QTNF_FW_STATE_ACTIVE || bus->fw_state == QTNF_FW_STATE_EP_DEAD) qtnf_core_detach(bus); priv = get_bus_priv(bus); netif_napi_del(&bus->mux_napi); flush_workqueue(priv->workqueue); destroy_workqueue(priv->workqueue); tasklet_kill(&priv->reclaim_tq); qtnf_free_xfer_buffers(priv); qtnf_debugfs_remove(bus); qtnf_pcie_free_shm_ipc(priv); qtnf_reset_card(priv); }
static void qtnf_pcie_pearl_remove(struct qtnf_bus *bus) { struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); qtnf_pearl_reset_ep(ps); qtnf_pearl_free_xfer_buffers(ps); }
static void qtnf_pcie_data_rx_stop(struct qtnf_bus *bus) { struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); napi_disable(&bus->mux_napi); qtnf_disable_hdp_irqs(ps); }
static void qtnf_pcie_data_tx_timeout(struct qtnf_bus *bus, struct net_device *ndev) { struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); tasklet_hi_schedule(&ps->base.reclaim_tq); }
static int qtnf_dbg_hdp_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); struct qtnf_pcie_bus_priv *priv = &ps->base; seq_printf(s, "tx_full_count(%u)\n", priv->tx_full_count); seq_printf(s, "tx_done_count(%u)\n", priv->tx_done_count); seq_printf(s, "tx_reclaim_done(%u)\n", priv->tx_reclaim_done); seq_printf(s, "tx_reclaim_req(%u)\n", priv->tx_reclaim_req); seq_printf(s, "tx_bd_r_index(%u)\n", priv->tx_bd_r_index); seq_printf(s, "tx_bd_p_index(%u)\n", readl(PCIE_HDP_RX0DMA_CNT(ps->pcie_reg_base)) & (priv->tx_bd_num - 1)); seq_printf(s, "tx_bd_w_index(%u)\n", priv->tx_bd_w_index); seq_printf(s, "tx queue len(%u)\n", CIRC_CNT(priv->tx_bd_w_index, priv->tx_bd_r_index, priv->tx_bd_num)); seq_printf(s, "rx_bd_r_index(%u)\n", priv->rx_bd_r_index); seq_printf(s, "rx_bd_p_index(%u)\n", readl(PCIE_HDP_TX0DMA_CNT(ps->pcie_reg_base)) & (priv->rx_bd_num - 1)); seq_printf(s, "rx_bd_w_index(%u)\n", priv->rx_bd_w_index); seq_printf(s, "rx alloc queue len(%u)\n", CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index, priv->rx_bd_num)); return 0; }
static void qtnf_pcie_bringup_fw_async(struct qtnf_bus *bus) { struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); struct pci_dev *pdev = priv->pdev; get_device(&pdev->dev); schedule_work(&bus->fw_work); }
static void qtnf_bringup_fw_async(struct qtnf_bus *bus) { struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); struct pci_dev *pdev = priv->pdev; get_device(&pdev->dev); INIT_WORK(&bus->fw_work, qtnf_fw_work_handler); schedule_work(&bus->fw_work); }
static int qtnf_dbg_mps_show(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); seq_printf(s, "%d\n", pcie_get_mps(priv->pdev)); return 0; }
static int qtnf_dbg_msi_show(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); seq_printf(s, "%u\n", priv->msi_enabled); return 0; }
static int qtnf_pcie_resume(struct device *dev) { struct qtnf_pcie_bus_priv *priv; struct qtnf_bus *bus; bus = pci_get_drvdata(to_pci_dev(dev)); if (!bus) return -EFAULT; priv = get_bus_priv(bus); return priv->resume_cb(bus); }
static int qtnf_pcie_control_tx(struct qtnf_bus *bus, struct sk_buff *skb) { struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); int ret; ret = qtnf_shm_ipc_send(&priv->shm_ipc_ep_in, skb->data, skb->len); if (ret == -ETIMEDOUT) { pr_err("EP firmware is dead\n"); bus->fw_state = QTNF_FW_STATE_EP_DEAD; } return ret; }
static int qtnf_pcie_pearl_probe(struct qtnf_bus *bus, unsigned int tx_bd_size) { struct qtnf_shm_ipc_int ipc_int; struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); struct pci_dev *pdev = ps->base.pdev; int ret; bus->bus_ops = &qtnf_pcie_pearl_bus_ops; spin_lock_init(&ps->irq_lock); INIT_WORK(&bus->fw_work, qtnf_pearl_fw_work_handler); ps->pcie_reg_base = ps->base.dmareg_bar; ps->bda = ps->base.epmem_bar; writel(ps->base.msi_enabled, &ps->bda->bda_rc_msi_enabled); ret = qtnf_pcie_pearl_init_xfer(ps, tx_bd_size); if (ret) { pr_err("PCIE xfer init failed\n"); return ret; } /* init default irq settings */ qtnf_init_hdp_irqs(ps); /* start with disabled irqs */ qtnf_disable_hdp_irqs(ps); ret = devm_request_irq(&pdev->dev, pdev->irq, &qtnf_pcie_pearl_interrupt, 0, "qtnf_pearl_irq", (void *)bus); if (ret) { pr_err("failed to request pcie irq %d\n", pdev->irq); qtnf_pearl_free_xfer_buffers(ps); return ret; } tasklet_init(&ps->base.reclaim_tq, qtnf_pearl_reclaim_tasklet_fn, (unsigned long)ps); netif_napi_add(&bus->mux_dev, &bus->mux_napi, qtnf_pcie_pearl_rx_poll, 10); ipc_int.fn = qtnf_pcie_pearl_ipc_gen_ep_int; ipc_int.arg = ps; qtnf_pcie_init_shm_ipc(&ps->base, &ps->bda->bda_shm_reg1, &ps->bda->bda_shm_reg2, &ipc_int); return 0; }
static int qtnf_dbg_shm_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); struct qtnf_pcie_bus_priv *priv = get_bus_priv(bus); seq_printf(s, "shm_ipc_ep_in.tx_packet_count(%zu)\n", priv->shm_ipc_ep_in.tx_packet_count); seq_printf(s, "shm_ipc_ep_in.rx_packet_count(%zu)\n", priv->shm_ipc_ep_in.rx_packet_count); seq_printf(s, "shm_ipc_ep_out.tx_packet_count(%zu)\n", priv->shm_ipc_ep_out.tx_timeout_count); seq_printf(s, "shm_ipc_ep_out.rx_packet_count(%zu)\n", priv->shm_ipc_ep_out.rx_packet_count); return 0; }
static irqreturn_t qtnf_pcie_pearl_interrupt(int irq, void *data) { struct qtnf_bus *bus = (struct qtnf_bus *)data; struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); struct qtnf_pcie_bus_priv *priv = &ps->base; u32 status; priv->pcie_irq_count++; status = readl(PCIE_HDP_INT_STATUS(ps->pcie_reg_base)); qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_in); qtnf_shm_ipc_irq_handler(&priv->shm_ipc_ep_out); if (!(status & ps->pcie_irq_mask)) goto irq_done; if (status & PCIE_HDP_INT_RX_BITS) ps->pcie_irq_rx_count++; if (status & PCIE_HDP_INT_TX_BITS) ps->pcie_irq_tx_count++; if (status & PCIE_HDP_INT_HHBM_UF) ps->pcie_irq_uf_count++; if (status & PCIE_HDP_INT_RX_BITS) { qtnf_dis_rxdone_irq(ps); napi_schedule(&bus->mux_napi); } if (status & PCIE_HDP_INT_TX_BITS) { qtnf_dis_txdone_irq(ps); tasklet_hi_schedule(&priv->reclaim_tq); } irq_done: /* H/W workaround: clean all bits, not only enabled */ qtnf_non_posted_write(~0U, PCIE_HDP_INT_STATUS(ps->pcie_reg_base)); if (!priv->msi_enabled) qtnf_deassert_intx(ps); return IRQ_HANDLED; }
struct qtnf_bus *qtnf_pcie_pearl_alloc(struct pci_dev *pdev) { struct qtnf_bus *bus; struct qtnf_pcie_pearl_state *ps; bus = devm_kzalloc(&pdev->dev, sizeof(*bus) + sizeof(*ps), GFP_KERNEL); if (!bus) return NULL; ps = get_bus_priv(bus); ps->base.probe_cb = qtnf_pcie_pearl_probe; ps->base.remove_cb = qtnf_pcie_pearl_remove; ps->base.dma_mask_get_cb = qtnf_pearl_dma_mask_get; #ifdef CONFIG_PM_SLEEP ps->base.resume_cb = qtnf_pcie_pearl_resume; ps->base.suspend_cb = qtnf_pcie_pearl_suspend; #endif return bus; }
static int qtnf_dbg_irq_stats(struct seq_file *s, void *data) { struct qtnf_bus *bus = dev_get_drvdata(s->private); struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); u32 reg = readl(PCIE_HDP_INT_EN(ps->pcie_reg_base)); u32 status; seq_printf(s, "pcie_irq_count(%u)\n", ps->base.pcie_irq_count); seq_printf(s, "pcie_irq_tx_count(%u)\n", ps->pcie_irq_tx_count); status = reg & PCIE_HDP_INT_TX_BITS; seq_printf(s, "pcie_irq_tx_status(%s)\n", (status == PCIE_HDP_INT_TX_BITS) ? "EN" : "DIS"); seq_printf(s, "pcie_irq_rx_count(%u)\n", ps->pcie_irq_rx_count); status = reg & PCIE_HDP_INT_RX_BITS; seq_printf(s, "pcie_irq_rx_status(%s)\n", (status == PCIE_HDP_INT_RX_BITS) ? "EN" : "DIS"); seq_printf(s, "pcie_irq_uf_count(%u)\n", ps->pcie_irq_uf_count); status = reg & PCIE_HDP_INT_HHBM_UF; seq_printf(s, "pcie_irq_hhbm_uf_status(%s)\n", (status == PCIE_HDP_INT_HHBM_UF) ? "EN" : "DIS"); return 0; }
static void qtnf_pearl_fw_work_handler(struct work_struct *work) { struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work); struct qtnf_pcie_pearl_state *ps = (void *)get_bus_priv(bus); u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; const char *fwname = QTN_PCI_PEARL_FW_NAME; struct pci_dev *pdev = ps->base.pdev; const struct firmware *fw; int ret; if (ps->base.flashboot) { state |= QTN_RC_FW_FLASHBOOT; } else { ret = request_firmware(&fw, fwname, &pdev->dev); if (ret < 0) { pr_err("failed to get firmware %s\n", fwname); goto fw_load_exit; } } qtnf_set_state(&ps->bda->bda_rc_state, state); if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY, QTN_FW_DL_TIMEOUT_MS)) { pr_err("card is not ready\n"); if (!ps->base.flashboot) release_firmware(fw); goto fw_load_exit; } qtnf_clear_state(&ps->bda->bda_ep_state, QTN_EP_FW_LOADRDY); if (ps->base.flashboot) { pr_info("booting firmware from flash\n"); } else { pr_info("starting firmware upload: %s\n", fwname); ret = qtnf_ep_fw_load(ps, fw->data, fw->size); release_firmware(fw); if (ret) { pr_err("firmware upload error\n"); goto fw_load_exit; } } if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_DONE, QTN_FW_DL_TIMEOUT_MS)) { pr_err("firmware bringup timed out\n"); goto fw_load_exit; } if (qtnf_poll_state(&ps->bda->bda_ep_state, QTN_EP_FW_QLINK_DONE, QTN_FW_QLINK_TIMEOUT_MS)) { pr_err("firmware runtime failure\n"); goto fw_load_exit; } pr_info("firmware is up and running\n"); ret = qtnf_pcie_fw_boot_done(bus); if (ret) goto fw_load_exit; qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); fw_load_exit: put_device(&pdev->dev); }
static void qtnf_fw_work_handler(struct work_struct *work) { struct qtnf_bus *bus = container_of(work, struct qtnf_bus, fw_work); struct qtnf_pcie_bus_priv *priv = (void *)get_bus_priv(bus); struct pci_dev *pdev = priv->pdev; const struct firmware *fw; int ret; u32 state = QTN_RC_FW_LOADRDY | QTN_RC_FW_QLINK; if (flashboot) { state |= QTN_RC_FW_FLASHBOOT; } else { ret = request_firmware(&fw, bus->fwname, &pdev->dev); if (ret < 0) { pr_err("failed to get firmware %s\n", bus->fwname); goto fw_load_fail; } } qtnf_set_state(&priv->bda->bda_rc_state, state); if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY, QTN_FW_DL_TIMEOUT_MS)) { pr_err("card is not ready\n"); if (!flashboot) release_firmware(fw); goto fw_load_fail; } qtnf_clear_state(&priv->bda->bda_ep_state, QTN_EP_FW_LOADRDY); if (flashboot) { pr_info("booting firmware from flash\n"); } else { pr_info("starting firmware upload: %s\n", bus->fwname); ret = qtnf_ep_fw_load(priv, fw->data, fw->size); release_firmware(fw); if (ret) { pr_err("firmware upload error\n"); goto fw_load_fail; } } if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_DONE, QTN_FW_DL_TIMEOUT_MS)) { pr_err("firmware bringup timed out\n"); goto fw_load_fail; } bus->fw_state = QTNF_FW_STATE_FW_DNLD_DONE; pr_info("firmware is up and running\n"); if (qtnf_poll_state(&priv->bda->bda_ep_state, QTN_EP_FW_QLINK_DONE, QTN_FW_QLINK_TIMEOUT_MS)) { pr_err("firmware runtime failure\n"); goto fw_load_fail; } ret = qtnf_core_attach(bus); if (ret) { pr_err("failed to attach core\n"); goto fw_load_fail; } qtnf_debugfs_init(bus, DRV_NAME); qtnf_debugfs_add_entry(bus, "mps", qtnf_dbg_mps_show); qtnf_debugfs_add_entry(bus, "msi_enabled", qtnf_dbg_msi_show); qtnf_debugfs_add_entry(bus, "hdp_stats", qtnf_dbg_hdp_stats); qtnf_debugfs_add_entry(bus, "irq_stats", qtnf_dbg_irq_stats); qtnf_debugfs_add_entry(bus, "shm_stats", qtnf_dbg_shm_stats); goto fw_load_exit; fw_load_fail: bus->fw_state = QTNF_FW_STATE_DETACHED; fw_load_exit: complete(&bus->firmware_init_complete); put_device(&pdev->dev); }
static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct qtnf_pcie_bus_priv *pcie_priv; struct qtnf_bus *bus; int ret; bus = devm_kzalloc(&pdev->dev, sizeof(*bus) + sizeof(*pcie_priv), GFP_KERNEL); if (!bus) return -ENOMEM; pcie_priv = get_bus_priv(bus); pci_set_drvdata(pdev, bus); bus->bus_ops = &qtnf_pcie_bus_ops; bus->dev = &pdev->dev; bus->fw_state = QTNF_FW_STATE_RESET; pcie_priv->pdev = pdev; strcpy(bus->fwname, QTN_PCI_PEARL_FW_NAME); init_completion(&bus->firmware_init_complete); mutex_init(&bus->bus_lock); spin_lock_init(&pcie_priv->tx0_lock); spin_lock_init(&pcie_priv->irq_lock); spin_lock_init(&pcie_priv->tx_reclaim_lock); /* init stats */ pcie_priv->tx_full_count = 0; pcie_priv->tx_done_count = 0; pcie_priv->pcie_irq_count = 0; pcie_priv->pcie_irq_rx_count = 0; pcie_priv->pcie_irq_tx_count = 0; pcie_priv->pcie_irq_uf_count = 0; pcie_priv->tx_reclaim_done = 0; pcie_priv->tx_reclaim_req = 0; tasklet_init(&pcie_priv->reclaim_tq, qtnf_reclaim_tasklet_fn, (unsigned long)pcie_priv); init_dummy_netdev(&bus->mux_dev); netif_napi_add(&bus->mux_dev, &bus->mux_napi, qtnf_rx_poll, 10); pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PEARL_PCIE"); if (!pcie_priv->workqueue) { pr_err("failed to alloc bus workqueue\n"); ret = -ENODEV; goto err_init; } if (!pci_is_pcie(pdev)) { pr_err("device %s is not PCI Express\n", pci_name(pdev)); ret = -EIO; goto err_base; } qtnf_tune_pcie_mps(pcie_priv); ret = pcim_enable_device(pdev); if (ret) { pr_err("failed to init PCI device %x\n", pdev->device); goto err_base; } else { pr_debug("successful init of PCI device %x\n", pdev->device); } #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(64)); #else ret = dma_set_mask_and_coherent(&pdev->dev, DMA_BIT_MASK(32)); #endif if (ret) { pr_err("PCIE DMA coherent mask init failed\n"); goto err_base; } pci_set_master(pdev); qtnf_pcie_init_irq(pcie_priv); ret = qtnf_pcie_init_memory(pcie_priv); if (ret < 0) { pr_err("PCIE memory init failed\n"); goto err_base; } pci_save_state(pdev); ret = qtnf_pcie_init_shm_ipc(pcie_priv); if (ret < 0) { pr_err("PCIE SHM IPC init failed\n"); goto err_base; } ret = qtnf_pcie_init_xfer(pcie_priv); if (ret) { pr_err("PCIE xfer init failed\n"); goto err_ipc; } /* init default irq settings */ qtnf_init_hdp_irqs(pcie_priv); /* start with disabled irqs */ qtnf_disable_hdp_irqs(pcie_priv); ret = devm_request_irq(&pdev->dev, pdev->irq, &qtnf_interrupt, 0, "qtnf_pcie_irq", (void *)bus); if (ret) { pr_err("failed to request pcie irq %d\n", pdev->irq); goto err_xfer; } qtnf_bringup_fw_async(bus); return 0; err_xfer: qtnf_free_xfer_buffers(pcie_priv); err_ipc: qtnf_pcie_free_shm_ipc(pcie_priv); err_base: flush_workqueue(pcie_priv->workqueue); destroy_workqueue(pcie_priv->workqueue); netif_napi_del(&bus->mux_napi); err_init: tasklet_kill(&pcie_priv->reclaim_tq); pci_set_drvdata(pdev, NULL); return ret; }
static int qtnf_pcie_pearl_rx_poll(struct napi_struct *napi, int budget) { struct qtnf_bus *bus = container_of(napi, struct qtnf_bus, mux_napi); struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); struct qtnf_pcie_bus_priv *priv = &ps->base; struct net_device *ndev = NULL; struct sk_buff *skb = NULL; int processed = 0; struct qtnf_pearl_rx_bd *rxbd; dma_addr_t skb_paddr; int consume; u32 descw; u32 psize; u16 r_idx; u16 w_idx; int ret; while (processed < budget) { if (!qtnf_rx_data_ready(ps)) goto rx_out; r_idx = priv->rx_bd_r_index; rxbd = &ps->rx_bd_vbase[r_idx]; descw = le32_to_cpu(rxbd->info); skb = priv->rx_skb[r_idx]; psize = QTN_GET_LEN(descw); consume = 1; if (!(descw & QTN_TXDONE_MASK)) { pr_warn("skip invalid rxbd[%d]\n", r_idx); consume = 0; } if (!skb) { pr_warn("skip missing rx_skb[%d]\n", r_idx); consume = 0; } if (skb && (skb_tailroom(skb) < psize)) { pr_err("skip packet with invalid length: %u > %u\n", psize, skb_tailroom(skb)); consume = 0; } if (skb) { skb_paddr = QTN_HOST_ADDR(le32_to_cpu(rxbd->addr_h), le32_to_cpu(rxbd->addr)); pci_unmap_single(priv->pdev, skb_paddr, SKB_BUF_SIZE, PCI_DMA_FROMDEVICE); } if (consume) { skb_put(skb, psize); ndev = qtnf_classify_skb(bus, skb); if (likely(ndev)) { qtnf_update_rx_stats(ndev, skb); skb->protocol = eth_type_trans(skb, ndev); napi_gro_receive(napi, skb); } else { pr_debug("drop untagged skb\n"); bus->mux_dev.stats.rx_dropped++; dev_kfree_skb_any(skb); } } else { if (skb) { bus->mux_dev.stats.rx_dropped++; dev_kfree_skb_any(skb); } } priv->rx_skb[r_idx] = NULL; if (++r_idx >= priv->rx_bd_num) r_idx = 0; priv->rx_bd_r_index = r_idx; /* repalce processed buffer by a new one */ w_idx = priv->rx_bd_w_index; while (CIRC_SPACE(priv->rx_bd_w_index, priv->rx_bd_r_index, priv->rx_bd_num) > 0) { if (++w_idx >= priv->rx_bd_num) w_idx = 0; ret = pearl_skb2rbd_attach(ps, w_idx); if (ret) { pr_err("failed to allocate new rx_skb[%d]\n", w_idx); break; } } processed++; } rx_out: if (processed < budget) { napi_complete(napi); qtnf_en_rxdone_irq(ps); } return processed; }
static int qtnf_pcie_data_tx(struct qtnf_bus *bus, struct sk_buff *skb) { struct qtnf_pcie_pearl_state *ps = get_bus_priv(bus); struct qtnf_pcie_bus_priv *priv = &ps->base; dma_addr_t txbd_paddr, skb_paddr; struct qtnf_pearl_tx_bd *txbd; unsigned long flags; int len, i; u32 info; int ret = 0; spin_lock_irqsave(&priv->tx_lock, flags); if (!qtnf_tx_queue_ready(ps)) { if (skb->dev) { netif_tx_stop_all_queues(skb->dev); priv->tx_stopped = 1; } spin_unlock_irqrestore(&priv->tx_lock, flags); return NETDEV_TX_BUSY; } i = priv->tx_bd_w_index; priv->tx_skb[i] = skb; len = skb->len; skb_paddr = pci_map_single(priv->pdev, skb->data, skb->len, PCI_DMA_TODEVICE); if (pci_dma_mapping_error(priv->pdev, skb_paddr)) { pr_err("skb DMA mapping error: %pad\n", &skb_paddr); ret = -ENOMEM; goto tx_done; } txbd = &ps->tx_bd_vbase[i]; txbd->addr = cpu_to_le32(QTN_HOST_LO32(skb_paddr)); txbd->addr_h = cpu_to_le32(QTN_HOST_HI32(skb_paddr)); info = (len & QTN_PCIE_TX_DESC_LEN_MASK) << QTN_PCIE_TX_DESC_LEN_SHIFT; txbd->info = cpu_to_le32(info); /* sync up all descriptor updates before passing them to EP */ dma_wmb(); /* write new TX descriptor to PCIE_RX_FIFO on EP */ txbd_paddr = ps->tx_bd_pbase + i * sizeof(struct qtnf_pearl_tx_bd); #ifdef CONFIG_ARCH_DMA_ADDR_T_64BIT writel(QTN_HOST_HI32(txbd_paddr), PCIE_HDP_HOST_WR_DESC0_H(ps->pcie_reg_base)); #endif writel(QTN_HOST_LO32(txbd_paddr), PCIE_HDP_HOST_WR_DESC0(ps->pcie_reg_base)); if (++i >= priv->tx_bd_num) i = 0; priv->tx_bd_w_index = i; tx_done: if (ret && skb) { pr_err_ratelimited("drop skb\n"); if (skb->dev) skb->dev->stats.tx_dropped++; dev_kfree_skb_any(skb); } priv->tx_done_count++; spin_unlock_irqrestore(&priv->tx_lock, flags); qtnf_pearl_data_tx_reclaim(ps); return NETDEV_TX_OK; }
static int qtnf_pcie_probe(struct pci_dev *pdev, const struct pci_device_id *id) { struct qtnf_pcie_bus_priv *pcie_priv; struct qtnf_bus *bus; void __iomem *sysctl_bar; void __iomem *epmem_bar; void __iomem *dmareg_bar; unsigned int chipid; int ret; if (!pci_is_pcie(pdev)) { pr_err("device %s is not PCI Express\n", pci_name(pdev)); return -EIO; } qtnf_tune_pcie_mps(pdev); ret = pcim_enable_device(pdev); if (ret) { pr_err("failed to init PCI device %x\n", pdev->device); return ret; } pci_set_master(pdev); sysctl_bar = qtnf_map_bar(pdev, QTN_SYSCTL_BAR); if (IS_ERR(sysctl_bar)) { pr_err("failed to map BAR%u\n", QTN_SYSCTL_BAR); return ret; } dmareg_bar = qtnf_map_bar(pdev, QTN_DMA_BAR); if (IS_ERR(dmareg_bar)) { pr_err("failed to map BAR%u\n", QTN_DMA_BAR); return ret; } epmem_bar = qtnf_map_bar(pdev, QTN_SHMEM_BAR); if (IS_ERR(epmem_bar)) { pr_err("failed to map BAR%u\n", QTN_SHMEM_BAR); return ret; } chipid = qtnf_chip_id_get(sysctl_bar); pr_info("identified device: %s\n", qtnf_chipid_to_string(chipid)); switch (chipid) { case QTN_CHIP_ID_PEARL: case QTN_CHIP_ID_PEARL_B: case QTN_CHIP_ID_PEARL_C: bus = qtnf_pcie_pearl_alloc(pdev); break; case QTN_CHIP_ID_TOPAZ: bus = qtnf_pcie_topaz_alloc(pdev); break; default: pr_err("unsupported chip ID 0x%x\n", chipid); return -ENOTSUPP; } if (!bus) return -ENOMEM; pcie_priv = get_bus_priv(bus); pci_set_drvdata(pdev, bus); bus->dev = &pdev->dev; bus->fw_state = QTNF_FW_STATE_RESET; pcie_priv->pdev = pdev; pcie_priv->tx_stopped = 0; pcie_priv->rx_bd_num = rx_bd_size_param; pcie_priv->flashboot = flashboot; if (fw_blksize_param > QTN_PCIE_MAX_FW_BUFSZ) pcie_priv->fw_blksize = QTN_PCIE_MAX_FW_BUFSZ; else pcie_priv->fw_blksize = fw_blksize_param; mutex_init(&bus->bus_lock); spin_lock_init(&pcie_priv->tx_lock); spin_lock_init(&pcie_priv->tx_reclaim_lock); pcie_priv->tx_full_count = 0; pcie_priv->tx_done_count = 0; pcie_priv->pcie_irq_count = 0; pcie_priv->tx_reclaim_done = 0; pcie_priv->tx_reclaim_req = 0; pcie_priv->workqueue = create_singlethread_workqueue("QTNF_PCIE"); if (!pcie_priv->workqueue) { pr_err("failed to alloc bus workqueue\n"); return -ENODEV; } ret = dma_set_mask_and_coherent(&pdev->dev, pcie_priv->dma_mask_get_cb()); if (ret) { pr_err("PCIE DMA coherent mask init failed 0x%llx\n", pcie_priv->dma_mask_get_cb()); goto error; } init_dummy_netdev(&bus->mux_dev); qtnf_pcie_init_irq(pcie_priv, use_msi); pcie_priv->sysctl_bar = sysctl_bar; pcie_priv->dmareg_bar = dmareg_bar; pcie_priv->epmem_bar = epmem_bar; pci_save_state(pdev); ret = pcie_priv->probe_cb(bus, tx_bd_size_param); if (ret) goto error; qtnf_pcie_bringup_fw_async(bus); return 0; error: flush_workqueue(pcie_priv->workqueue); destroy_workqueue(pcie_priv->workqueue); pci_set_drvdata(pdev, NULL); return ret; }