162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0 262306a36Sopenharmony_ci/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */ 362306a36Sopenharmony_ci 462306a36Sopenharmony_ci#include <linux/kernel.h> 562306a36Sopenharmony_ci#include <linux/types.h> 662306a36Sopenharmony_ci#include <linux/errno.h> 762306a36Sopenharmony_ci#include <linux/io.h> 862306a36Sopenharmony_ci#include <linux/slab.h> 962306a36Sopenharmony_ci#include <linux/etherdevice.h> 1062306a36Sopenharmony_ci#include "ionic.h" 1162306a36Sopenharmony_ci#include "ionic_dev.h" 1262306a36Sopenharmony_ci#include "ionic_lif.h" 1362306a36Sopenharmony_ci 1462306a36Sopenharmony_cistatic void ionic_watchdog_cb(struct timer_list *t) 1562306a36Sopenharmony_ci{ 1662306a36Sopenharmony_ci struct ionic *ionic = from_timer(ionic, t, watchdog_timer); 1762306a36Sopenharmony_ci struct ionic_lif *lif = ionic->lif; 1862306a36Sopenharmony_ci struct ionic_deferred_work *work; 1962306a36Sopenharmony_ci int hb; 2062306a36Sopenharmony_ci 2162306a36Sopenharmony_ci mod_timer(&ionic->watchdog_timer, 2262306a36Sopenharmony_ci round_jiffies(jiffies + ionic->watchdog_period)); 2362306a36Sopenharmony_ci 2462306a36Sopenharmony_ci if (!lif) 2562306a36Sopenharmony_ci return; 2662306a36Sopenharmony_ci 2762306a36Sopenharmony_ci hb = ionic_heartbeat_check(ionic); 2862306a36Sopenharmony_ci dev_dbg(ionic->dev, "%s: hb %d running %d UP %d\n", 2962306a36Sopenharmony_ci __func__, hb, netif_running(lif->netdev), 3062306a36Sopenharmony_ci test_bit(IONIC_LIF_F_UP, lif->state)); 3162306a36Sopenharmony_ci 3262306a36Sopenharmony_ci if (hb >= 0 && 3362306a36Sopenharmony_ci !test_bit(IONIC_LIF_F_FW_RESET, lif->state)) 3462306a36Sopenharmony_ci ionic_link_status_check_request(lif, CAN_NOT_SLEEP); 3562306a36Sopenharmony_ci 3662306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_FILTER_SYNC_NEEDED, lif->state) && 3762306a36Sopenharmony_ci !test_bit(IONIC_LIF_F_FW_RESET, lif->state)) { 3862306a36Sopenharmony_ci work = kzalloc(sizeof(*work), GFP_ATOMIC); 3962306a36Sopenharmony_ci if (!work) { 4062306a36Sopenharmony_ci netdev_err(lif->netdev, "rxmode change dropped\n"); 4162306a36Sopenharmony_ci return; 4262306a36Sopenharmony_ci } 4362306a36Sopenharmony_ci 4462306a36Sopenharmony_ci work->type = IONIC_DW_TYPE_RX_MODE; 4562306a36Sopenharmony_ci netdev_dbg(lif->netdev, "deferred: rx_mode\n"); 4662306a36Sopenharmony_ci ionic_lif_deferred_enqueue(&lif->deferred, work); 4762306a36Sopenharmony_ci } 4862306a36Sopenharmony_ci} 4962306a36Sopenharmony_ci 5062306a36Sopenharmony_cistatic void ionic_watchdog_init(struct ionic *ionic) 5162306a36Sopenharmony_ci{ 5262306a36Sopenharmony_ci struct ionic_dev *idev = &ionic->idev; 5362306a36Sopenharmony_ci 5462306a36Sopenharmony_ci timer_setup(&ionic->watchdog_timer, ionic_watchdog_cb, 0); 5562306a36Sopenharmony_ci ionic->watchdog_period = IONIC_WATCHDOG_SECS * HZ; 5662306a36Sopenharmony_ci 5762306a36Sopenharmony_ci /* set times to ensure the first check will proceed */ 5862306a36Sopenharmony_ci atomic_long_set(&idev->last_check_time, jiffies - 2 * HZ); 5962306a36Sopenharmony_ci idev->last_hb_time = jiffies - 2 * ionic->watchdog_period; 6062306a36Sopenharmony_ci /* init as ready, so no transition if the first check succeeds */ 6162306a36Sopenharmony_ci idev->last_fw_hb = 0; 6262306a36Sopenharmony_ci idev->fw_hb_ready = true; 6362306a36Sopenharmony_ci idev->fw_status_ready = true; 6462306a36Sopenharmony_ci idev->fw_generation = IONIC_FW_STS_F_GENERATION & 6562306a36Sopenharmony_ci ioread8(&idev->dev_info_regs->fw_status); 6662306a36Sopenharmony_ci} 6762306a36Sopenharmony_ci 6862306a36Sopenharmony_civoid ionic_init_devinfo(struct ionic *ionic) 6962306a36Sopenharmony_ci{ 7062306a36Sopenharmony_ci struct ionic_dev *idev = &ionic->idev; 7162306a36Sopenharmony_ci 7262306a36Sopenharmony_ci idev->dev_info.asic_type = ioread8(&idev->dev_info_regs->asic_type); 7362306a36Sopenharmony_ci idev->dev_info.asic_rev = ioread8(&idev->dev_info_regs->asic_rev); 7462306a36Sopenharmony_ci 7562306a36Sopenharmony_ci memcpy_fromio(idev->dev_info.fw_version, 7662306a36Sopenharmony_ci idev->dev_info_regs->fw_version, 7762306a36Sopenharmony_ci IONIC_DEVINFO_FWVERS_BUFLEN); 7862306a36Sopenharmony_ci 7962306a36Sopenharmony_ci memcpy_fromio(idev->dev_info.serial_num, 8062306a36Sopenharmony_ci idev->dev_info_regs->serial_num, 8162306a36Sopenharmony_ci IONIC_DEVINFO_SERIAL_BUFLEN); 8262306a36Sopenharmony_ci 8362306a36Sopenharmony_ci idev->dev_info.fw_version[IONIC_DEVINFO_FWVERS_BUFLEN] = 0; 8462306a36Sopenharmony_ci idev->dev_info.serial_num[IONIC_DEVINFO_SERIAL_BUFLEN] = 0; 8562306a36Sopenharmony_ci 8662306a36Sopenharmony_ci dev_dbg(ionic->dev, "fw_version %s\n", idev->dev_info.fw_version); 8762306a36Sopenharmony_ci} 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ciint ionic_dev_setup(struct ionic *ionic) 9062306a36Sopenharmony_ci{ 9162306a36Sopenharmony_ci struct ionic_dev_bar *bar = ionic->bars; 9262306a36Sopenharmony_ci unsigned int num_bars = ionic->num_bars; 9362306a36Sopenharmony_ci struct ionic_dev *idev = &ionic->idev; 9462306a36Sopenharmony_ci struct device *dev = ionic->dev; 9562306a36Sopenharmony_ci int size; 9662306a36Sopenharmony_ci u32 sig; 9762306a36Sopenharmony_ci 9862306a36Sopenharmony_ci /* BAR0: dev_cmd and interrupts */ 9962306a36Sopenharmony_ci if (num_bars < 1) { 10062306a36Sopenharmony_ci dev_err(dev, "No bars found, aborting\n"); 10162306a36Sopenharmony_ci return -EFAULT; 10262306a36Sopenharmony_ci } 10362306a36Sopenharmony_ci 10462306a36Sopenharmony_ci if (bar->len < IONIC_BAR0_SIZE) { 10562306a36Sopenharmony_ci dev_err(dev, "Resource bar size %lu too small, aborting\n", 10662306a36Sopenharmony_ci bar->len); 10762306a36Sopenharmony_ci return -EFAULT; 10862306a36Sopenharmony_ci } 10962306a36Sopenharmony_ci 11062306a36Sopenharmony_ci idev->dev_info_regs = bar->vaddr + IONIC_BAR0_DEV_INFO_REGS_OFFSET; 11162306a36Sopenharmony_ci idev->dev_cmd_regs = bar->vaddr + IONIC_BAR0_DEV_CMD_REGS_OFFSET; 11262306a36Sopenharmony_ci idev->intr_status = bar->vaddr + IONIC_BAR0_INTR_STATUS_OFFSET; 11362306a36Sopenharmony_ci idev->intr_ctrl = bar->vaddr + IONIC_BAR0_INTR_CTRL_OFFSET; 11462306a36Sopenharmony_ci 11562306a36Sopenharmony_ci idev->hwstamp_regs = &idev->dev_info_regs->hwstamp; 11662306a36Sopenharmony_ci 11762306a36Sopenharmony_ci sig = ioread32(&idev->dev_info_regs->signature); 11862306a36Sopenharmony_ci if (sig != IONIC_DEV_INFO_SIGNATURE) { 11962306a36Sopenharmony_ci dev_err(dev, "Incompatible firmware signature %x", sig); 12062306a36Sopenharmony_ci return -EFAULT; 12162306a36Sopenharmony_ci } 12262306a36Sopenharmony_ci 12362306a36Sopenharmony_ci ionic_init_devinfo(ionic); 12462306a36Sopenharmony_ci 12562306a36Sopenharmony_ci /* BAR1: doorbells */ 12662306a36Sopenharmony_ci bar++; 12762306a36Sopenharmony_ci if (num_bars < 2) { 12862306a36Sopenharmony_ci dev_err(dev, "Doorbell bar missing, aborting\n"); 12962306a36Sopenharmony_ci return -EFAULT; 13062306a36Sopenharmony_ci } 13162306a36Sopenharmony_ci 13262306a36Sopenharmony_ci ionic_watchdog_init(ionic); 13362306a36Sopenharmony_ci 13462306a36Sopenharmony_ci idev->db_pages = bar->vaddr; 13562306a36Sopenharmony_ci idev->phy_db_pages = bar->bus_addr; 13662306a36Sopenharmony_ci 13762306a36Sopenharmony_ci /* BAR2: optional controller memory mapping */ 13862306a36Sopenharmony_ci bar++; 13962306a36Sopenharmony_ci mutex_init(&idev->cmb_inuse_lock); 14062306a36Sopenharmony_ci if (num_bars < 3 || !ionic->bars[IONIC_PCI_BAR_CMB].len) { 14162306a36Sopenharmony_ci idev->cmb_inuse = NULL; 14262306a36Sopenharmony_ci return 0; 14362306a36Sopenharmony_ci } 14462306a36Sopenharmony_ci 14562306a36Sopenharmony_ci idev->phy_cmb_pages = bar->bus_addr; 14662306a36Sopenharmony_ci idev->cmb_npages = bar->len / PAGE_SIZE; 14762306a36Sopenharmony_ci size = BITS_TO_LONGS(idev->cmb_npages) * sizeof(long); 14862306a36Sopenharmony_ci idev->cmb_inuse = kzalloc(size, GFP_KERNEL); 14962306a36Sopenharmony_ci if (!idev->cmb_inuse) 15062306a36Sopenharmony_ci dev_warn(dev, "No memory for CMB, disabling\n"); 15162306a36Sopenharmony_ci 15262306a36Sopenharmony_ci return 0; 15362306a36Sopenharmony_ci} 15462306a36Sopenharmony_ci 15562306a36Sopenharmony_civoid ionic_dev_teardown(struct ionic *ionic) 15662306a36Sopenharmony_ci{ 15762306a36Sopenharmony_ci struct ionic_dev *idev = &ionic->idev; 15862306a36Sopenharmony_ci 15962306a36Sopenharmony_ci kfree(idev->cmb_inuse); 16062306a36Sopenharmony_ci idev->cmb_inuse = NULL; 16162306a36Sopenharmony_ci idev->phy_cmb_pages = 0; 16262306a36Sopenharmony_ci idev->cmb_npages = 0; 16362306a36Sopenharmony_ci 16462306a36Sopenharmony_ci mutex_destroy(&idev->cmb_inuse_lock); 16562306a36Sopenharmony_ci} 16662306a36Sopenharmony_ci 16762306a36Sopenharmony_ci/* Devcmd Interface */ 16862306a36Sopenharmony_cibool ionic_is_fw_running(struct ionic_dev *idev) 16962306a36Sopenharmony_ci{ 17062306a36Sopenharmony_ci u8 fw_status = ioread8(&idev->dev_info_regs->fw_status); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* firmware is useful only if the running bit is set and 17362306a36Sopenharmony_ci * fw_status != 0xff (bad PCI read) 17462306a36Sopenharmony_ci */ 17562306a36Sopenharmony_ci return (fw_status != 0xff) && (fw_status & IONIC_FW_STS_F_RUNNING); 17662306a36Sopenharmony_ci} 17762306a36Sopenharmony_ci 17862306a36Sopenharmony_ciint ionic_heartbeat_check(struct ionic *ionic) 17962306a36Sopenharmony_ci{ 18062306a36Sopenharmony_ci unsigned long check_time, last_check_time; 18162306a36Sopenharmony_ci struct ionic_dev *idev = &ionic->idev; 18262306a36Sopenharmony_ci struct ionic_lif *lif = ionic->lif; 18362306a36Sopenharmony_ci bool fw_status_ready = true; 18462306a36Sopenharmony_ci bool fw_hb_ready; 18562306a36Sopenharmony_ci u8 fw_generation; 18662306a36Sopenharmony_ci u8 fw_status; 18762306a36Sopenharmony_ci u32 fw_hb; 18862306a36Sopenharmony_ci 18962306a36Sopenharmony_ci /* wait a least one second before testing again */ 19062306a36Sopenharmony_ci check_time = jiffies; 19162306a36Sopenharmony_ci last_check_time = atomic_long_read(&idev->last_check_time); 19262306a36Sopenharmony_cido_check_time: 19362306a36Sopenharmony_ci if (time_before(check_time, last_check_time + HZ)) 19462306a36Sopenharmony_ci return 0; 19562306a36Sopenharmony_ci if (!atomic_long_try_cmpxchg_relaxed(&idev->last_check_time, 19662306a36Sopenharmony_ci &last_check_time, check_time)) { 19762306a36Sopenharmony_ci /* if called concurrently, only the first should proceed. */ 19862306a36Sopenharmony_ci dev_dbg(ionic->dev, "%s: do_check_time again\n", __func__); 19962306a36Sopenharmony_ci goto do_check_time; 20062306a36Sopenharmony_ci } 20162306a36Sopenharmony_ci 20262306a36Sopenharmony_ci fw_status = ioread8(&idev->dev_info_regs->fw_status); 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_ci /* If fw_status is not ready don't bother with the generation */ 20562306a36Sopenharmony_ci if (!ionic_is_fw_running(idev)) { 20662306a36Sopenharmony_ci fw_status_ready = false; 20762306a36Sopenharmony_ci } else { 20862306a36Sopenharmony_ci fw_generation = fw_status & IONIC_FW_STS_F_GENERATION; 20962306a36Sopenharmony_ci if (idev->fw_generation != fw_generation) { 21062306a36Sopenharmony_ci dev_info(ionic->dev, "FW generation 0x%02x -> 0x%02x\n", 21162306a36Sopenharmony_ci idev->fw_generation, fw_generation); 21262306a36Sopenharmony_ci 21362306a36Sopenharmony_ci idev->fw_generation = fw_generation; 21462306a36Sopenharmony_ci 21562306a36Sopenharmony_ci /* If the generation changed, the fw status is not 21662306a36Sopenharmony_ci * ready so we need to trigger a fw-down cycle. After 21762306a36Sopenharmony_ci * the down, the next watchdog will see the fw is up 21862306a36Sopenharmony_ci * and the generation value stable, so will trigger 21962306a36Sopenharmony_ci * the fw-up activity. 22062306a36Sopenharmony_ci * 22162306a36Sopenharmony_ci * If we had already moved to FW_RESET from a RESET event, 22262306a36Sopenharmony_ci * it is possible that we never saw the fw_status go to 0, 22362306a36Sopenharmony_ci * so we fake the current idev->fw_status_ready here to 22462306a36Sopenharmony_ci * force the transition and get FW up again. 22562306a36Sopenharmony_ci */ 22662306a36Sopenharmony_ci if (test_bit(IONIC_LIF_F_FW_RESET, lif->state)) 22762306a36Sopenharmony_ci idev->fw_status_ready = false; /* go to running */ 22862306a36Sopenharmony_ci else 22962306a36Sopenharmony_ci fw_status_ready = false; /* go to down */ 23062306a36Sopenharmony_ci } 23162306a36Sopenharmony_ci } 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_ci dev_dbg(ionic->dev, "fw_status 0x%02x ready %d idev->ready %d last_hb 0x%x state 0x%02lx\n", 23462306a36Sopenharmony_ci fw_status, fw_status_ready, idev->fw_status_ready, 23562306a36Sopenharmony_ci idev->last_fw_hb, lif->state[0]); 23662306a36Sopenharmony_ci 23762306a36Sopenharmony_ci /* is this a transition? */ 23862306a36Sopenharmony_ci if (fw_status_ready != idev->fw_status_ready && 23962306a36Sopenharmony_ci !test_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) { 24062306a36Sopenharmony_ci bool trigger = false; 24162306a36Sopenharmony_ci 24262306a36Sopenharmony_ci idev->fw_status_ready = fw_status_ready; 24362306a36Sopenharmony_ci 24462306a36Sopenharmony_ci if (!fw_status_ready && 24562306a36Sopenharmony_ci !test_bit(IONIC_LIF_F_FW_RESET, lif->state) && 24662306a36Sopenharmony_ci !test_and_set_bit(IONIC_LIF_F_FW_STOPPING, lif->state)) { 24762306a36Sopenharmony_ci dev_info(ionic->dev, "FW stopped 0x%02x\n", fw_status); 24862306a36Sopenharmony_ci trigger = true; 24962306a36Sopenharmony_ci 25062306a36Sopenharmony_ci } else if (fw_status_ready && 25162306a36Sopenharmony_ci test_bit(IONIC_LIF_F_FW_RESET, lif->state)) { 25262306a36Sopenharmony_ci dev_info(ionic->dev, "FW running 0x%02x\n", fw_status); 25362306a36Sopenharmony_ci trigger = true; 25462306a36Sopenharmony_ci } 25562306a36Sopenharmony_ci 25662306a36Sopenharmony_ci if (trigger) { 25762306a36Sopenharmony_ci struct ionic_deferred_work *work; 25862306a36Sopenharmony_ci 25962306a36Sopenharmony_ci work = kzalloc(sizeof(*work), GFP_ATOMIC); 26062306a36Sopenharmony_ci if (work) { 26162306a36Sopenharmony_ci work->type = IONIC_DW_TYPE_LIF_RESET; 26262306a36Sopenharmony_ci work->fw_status = fw_status_ready; 26362306a36Sopenharmony_ci ionic_lif_deferred_enqueue(&lif->deferred, work); 26462306a36Sopenharmony_ci } 26562306a36Sopenharmony_ci } 26662306a36Sopenharmony_ci } 26762306a36Sopenharmony_ci 26862306a36Sopenharmony_ci if (!idev->fw_status_ready) 26962306a36Sopenharmony_ci return -ENXIO; 27062306a36Sopenharmony_ci 27162306a36Sopenharmony_ci /* Because of some variability in the actual FW heartbeat, we 27262306a36Sopenharmony_ci * wait longer than the DEVCMD_TIMEOUT before checking again. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ci last_check_time = idev->last_hb_time; 27562306a36Sopenharmony_ci if (time_before(check_time, last_check_time + DEVCMD_TIMEOUT * 2 * HZ)) 27662306a36Sopenharmony_ci return 0; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci fw_hb = ioread32(&idev->dev_info_regs->fw_heartbeat); 27962306a36Sopenharmony_ci fw_hb_ready = fw_hb != idev->last_fw_hb; 28062306a36Sopenharmony_ci 28162306a36Sopenharmony_ci /* early FW version had no heartbeat, so fake it */ 28262306a36Sopenharmony_ci if (!fw_hb_ready && !fw_hb) 28362306a36Sopenharmony_ci fw_hb_ready = true; 28462306a36Sopenharmony_ci 28562306a36Sopenharmony_ci dev_dbg(ionic->dev, "%s: fw_hb %u last_fw_hb %u ready %u\n", 28662306a36Sopenharmony_ci __func__, fw_hb, idev->last_fw_hb, fw_hb_ready); 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci idev->last_fw_hb = fw_hb; 28962306a36Sopenharmony_ci 29062306a36Sopenharmony_ci /* log a transition */ 29162306a36Sopenharmony_ci if (fw_hb_ready != idev->fw_hb_ready) { 29262306a36Sopenharmony_ci idev->fw_hb_ready = fw_hb_ready; 29362306a36Sopenharmony_ci if (!fw_hb_ready) 29462306a36Sopenharmony_ci dev_info(ionic->dev, "FW heartbeat stalled at %d\n", fw_hb); 29562306a36Sopenharmony_ci else 29662306a36Sopenharmony_ci dev_info(ionic->dev, "FW heartbeat restored at %d\n", fw_hb); 29762306a36Sopenharmony_ci } 29862306a36Sopenharmony_ci 29962306a36Sopenharmony_ci if (!fw_hb_ready) 30062306a36Sopenharmony_ci return -ENXIO; 30162306a36Sopenharmony_ci 30262306a36Sopenharmony_ci idev->last_hb_time = check_time; 30362306a36Sopenharmony_ci 30462306a36Sopenharmony_ci return 0; 30562306a36Sopenharmony_ci} 30662306a36Sopenharmony_ci 30762306a36Sopenharmony_ciu8 ionic_dev_cmd_status(struct ionic_dev *idev) 30862306a36Sopenharmony_ci{ 30962306a36Sopenharmony_ci return ioread8(&idev->dev_cmd_regs->comp.comp.status); 31062306a36Sopenharmony_ci} 31162306a36Sopenharmony_ci 31262306a36Sopenharmony_cibool ionic_dev_cmd_done(struct ionic_dev *idev) 31362306a36Sopenharmony_ci{ 31462306a36Sopenharmony_ci return ioread32(&idev->dev_cmd_regs->done) & IONIC_DEV_CMD_DONE; 31562306a36Sopenharmony_ci} 31662306a36Sopenharmony_ci 31762306a36Sopenharmony_civoid ionic_dev_cmd_comp(struct ionic_dev *idev, union ionic_dev_cmd_comp *comp) 31862306a36Sopenharmony_ci{ 31962306a36Sopenharmony_ci memcpy_fromio(comp, &idev->dev_cmd_regs->comp, sizeof(*comp)); 32062306a36Sopenharmony_ci} 32162306a36Sopenharmony_ci 32262306a36Sopenharmony_civoid ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd) 32362306a36Sopenharmony_ci{ 32462306a36Sopenharmony_ci idev->opcode = cmd->cmd.opcode; 32562306a36Sopenharmony_ci memcpy_toio(&idev->dev_cmd_regs->cmd, cmd, sizeof(*cmd)); 32662306a36Sopenharmony_ci iowrite32(0, &idev->dev_cmd_regs->done); 32762306a36Sopenharmony_ci iowrite32(1, &idev->dev_cmd_regs->doorbell); 32862306a36Sopenharmony_ci} 32962306a36Sopenharmony_ci 33062306a36Sopenharmony_ci/* Device commands */ 33162306a36Sopenharmony_civoid ionic_dev_cmd_identify(struct ionic_dev *idev, u8 ver) 33262306a36Sopenharmony_ci{ 33362306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 33462306a36Sopenharmony_ci .identify.opcode = IONIC_CMD_IDENTIFY, 33562306a36Sopenharmony_ci .identify.ver = ver, 33662306a36Sopenharmony_ci }; 33762306a36Sopenharmony_ci 33862306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 33962306a36Sopenharmony_ci} 34062306a36Sopenharmony_ci 34162306a36Sopenharmony_civoid ionic_dev_cmd_init(struct ionic_dev *idev) 34262306a36Sopenharmony_ci{ 34362306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 34462306a36Sopenharmony_ci .init.opcode = IONIC_CMD_INIT, 34562306a36Sopenharmony_ci .init.type = 0, 34662306a36Sopenharmony_ci }; 34762306a36Sopenharmony_ci 34862306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 34962306a36Sopenharmony_ci} 35062306a36Sopenharmony_ci 35162306a36Sopenharmony_civoid ionic_dev_cmd_reset(struct ionic_dev *idev) 35262306a36Sopenharmony_ci{ 35362306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 35462306a36Sopenharmony_ci .reset.opcode = IONIC_CMD_RESET, 35562306a36Sopenharmony_ci }; 35662306a36Sopenharmony_ci 35762306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 35862306a36Sopenharmony_ci} 35962306a36Sopenharmony_ci 36062306a36Sopenharmony_ci/* Port commands */ 36162306a36Sopenharmony_civoid ionic_dev_cmd_port_identify(struct ionic_dev *idev) 36262306a36Sopenharmony_ci{ 36362306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 36462306a36Sopenharmony_ci .port_init.opcode = IONIC_CMD_PORT_IDENTIFY, 36562306a36Sopenharmony_ci .port_init.index = 0, 36662306a36Sopenharmony_ci }; 36762306a36Sopenharmony_ci 36862306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 36962306a36Sopenharmony_ci} 37062306a36Sopenharmony_ci 37162306a36Sopenharmony_civoid ionic_dev_cmd_port_init(struct ionic_dev *idev) 37262306a36Sopenharmony_ci{ 37362306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 37462306a36Sopenharmony_ci .port_init.opcode = IONIC_CMD_PORT_INIT, 37562306a36Sopenharmony_ci .port_init.index = 0, 37662306a36Sopenharmony_ci .port_init.info_pa = cpu_to_le64(idev->port_info_pa), 37762306a36Sopenharmony_ci }; 37862306a36Sopenharmony_ci 37962306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 38062306a36Sopenharmony_ci} 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_civoid ionic_dev_cmd_port_reset(struct ionic_dev *idev) 38362306a36Sopenharmony_ci{ 38462306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 38562306a36Sopenharmony_ci .port_reset.opcode = IONIC_CMD_PORT_RESET, 38662306a36Sopenharmony_ci .port_reset.index = 0, 38762306a36Sopenharmony_ci }; 38862306a36Sopenharmony_ci 38962306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 39062306a36Sopenharmony_ci} 39162306a36Sopenharmony_ci 39262306a36Sopenharmony_civoid ionic_dev_cmd_port_state(struct ionic_dev *idev, u8 state) 39362306a36Sopenharmony_ci{ 39462306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 39562306a36Sopenharmony_ci .port_setattr.opcode = IONIC_CMD_PORT_SETATTR, 39662306a36Sopenharmony_ci .port_setattr.index = 0, 39762306a36Sopenharmony_ci .port_setattr.attr = IONIC_PORT_ATTR_STATE, 39862306a36Sopenharmony_ci .port_setattr.state = state, 39962306a36Sopenharmony_ci }; 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ci 40462306a36Sopenharmony_civoid ionic_dev_cmd_port_speed(struct ionic_dev *idev, u32 speed) 40562306a36Sopenharmony_ci{ 40662306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 40762306a36Sopenharmony_ci .port_setattr.opcode = IONIC_CMD_PORT_SETATTR, 40862306a36Sopenharmony_ci .port_setattr.index = 0, 40962306a36Sopenharmony_ci .port_setattr.attr = IONIC_PORT_ATTR_SPEED, 41062306a36Sopenharmony_ci .port_setattr.speed = cpu_to_le32(speed), 41162306a36Sopenharmony_ci }; 41262306a36Sopenharmony_ci 41362306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 41462306a36Sopenharmony_ci} 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_civoid ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, u8 an_enable) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 41962306a36Sopenharmony_ci .port_setattr.opcode = IONIC_CMD_PORT_SETATTR, 42062306a36Sopenharmony_ci .port_setattr.index = 0, 42162306a36Sopenharmony_ci .port_setattr.attr = IONIC_PORT_ATTR_AUTONEG, 42262306a36Sopenharmony_ci .port_setattr.an_enable = an_enable, 42362306a36Sopenharmony_ci }; 42462306a36Sopenharmony_ci 42562306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 42662306a36Sopenharmony_ci} 42762306a36Sopenharmony_ci 42862306a36Sopenharmony_civoid ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type) 42962306a36Sopenharmony_ci{ 43062306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 43162306a36Sopenharmony_ci .port_setattr.opcode = IONIC_CMD_PORT_SETATTR, 43262306a36Sopenharmony_ci .port_setattr.index = 0, 43362306a36Sopenharmony_ci .port_setattr.attr = IONIC_PORT_ATTR_FEC, 43462306a36Sopenharmony_ci .port_setattr.fec_type = fec_type, 43562306a36Sopenharmony_ci }; 43662306a36Sopenharmony_ci 43762306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 43862306a36Sopenharmony_ci} 43962306a36Sopenharmony_ci 44062306a36Sopenharmony_civoid ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type) 44162306a36Sopenharmony_ci{ 44262306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 44362306a36Sopenharmony_ci .port_setattr.opcode = IONIC_CMD_PORT_SETATTR, 44462306a36Sopenharmony_ci .port_setattr.index = 0, 44562306a36Sopenharmony_ci .port_setattr.attr = IONIC_PORT_ATTR_PAUSE, 44662306a36Sopenharmony_ci .port_setattr.pause_type = pause_type, 44762306a36Sopenharmony_ci }; 44862306a36Sopenharmony_ci 44962306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 45062306a36Sopenharmony_ci} 45162306a36Sopenharmony_ci 45262306a36Sopenharmony_ci/* VF commands */ 45362306a36Sopenharmony_ciint ionic_set_vf_config(struct ionic *ionic, int vf, 45462306a36Sopenharmony_ci struct ionic_vf_setattr_cmd *vfc) 45562306a36Sopenharmony_ci{ 45662306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 45762306a36Sopenharmony_ci .vf_setattr.opcode = IONIC_CMD_VF_SETATTR, 45862306a36Sopenharmony_ci .vf_setattr.attr = vfc->attr, 45962306a36Sopenharmony_ci .vf_setattr.vf_index = cpu_to_le16(vf), 46062306a36Sopenharmony_ci }; 46162306a36Sopenharmony_ci int err; 46262306a36Sopenharmony_ci 46362306a36Sopenharmony_ci memcpy(cmd.vf_setattr.pad, vfc->pad, sizeof(vfc->pad)); 46462306a36Sopenharmony_ci 46562306a36Sopenharmony_ci mutex_lock(&ionic->dev_cmd_lock); 46662306a36Sopenharmony_ci ionic_dev_cmd_go(&ionic->idev, &cmd); 46762306a36Sopenharmony_ci err = ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); 46862306a36Sopenharmony_ci mutex_unlock(&ionic->dev_cmd_lock); 46962306a36Sopenharmony_ci 47062306a36Sopenharmony_ci return err; 47162306a36Sopenharmony_ci} 47262306a36Sopenharmony_ci 47362306a36Sopenharmony_ciint ionic_dev_cmd_vf_getattr(struct ionic *ionic, int vf, u8 attr, 47462306a36Sopenharmony_ci struct ionic_vf_getattr_comp *comp) 47562306a36Sopenharmony_ci{ 47662306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 47762306a36Sopenharmony_ci .vf_getattr.opcode = IONIC_CMD_VF_GETATTR, 47862306a36Sopenharmony_ci .vf_getattr.attr = attr, 47962306a36Sopenharmony_ci .vf_getattr.vf_index = cpu_to_le16(vf), 48062306a36Sopenharmony_ci }; 48162306a36Sopenharmony_ci int err; 48262306a36Sopenharmony_ci 48362306a36Sopenharmony_ci if (vf >= ionic->num_vfs) 48462306a36Sopenharmony_ci return -EINVAL; 48562306a36Sopenharmony_ci 48662306a36Sopenharmony_ci switch (attr) { 48762306a36Sopenharmony_ci case IONIC_VF_ATTR_SPOOFCHK: 48862306a36Sopenharmony_ci case IONIC_VF_ATTR_TRUST: 48962306a36Sopenharmony_ci case IONIC_VF_ATTR_LINKSTATE: 49062306a36Sopenharmony_ci case IONIC_VF_ATTR_MAC: 49162306a36Sopenharmony_ci case IONIC_VF_ATTR_VLAN: 49262306a36Sopenharmony_ci case IONIC_VF_ATTR_RATE: 49362306a36Sopenharmony_ci break; 49462306a36Sopenharmony_ci case IONIC_VF_ATTR_STATSADDR: 49562306a36Sopenharmony_ci default: 49662306a36Sopenharmony_ci return -EINVAL; 49762306a36Sopenharmony_ci } 49862306a36Sopenharmony_ci 49962306a36Sopenharmony_ci mutex_lock(&ionic->dev_cmd_lock); 50062306a36Sopenharmony_ci ionic_dev_cmd_go(&ionic->idev, &cmd); 50162306a36Sopenharmony_ci err = ionic_dev_cmd_wait_nomsg(ionic, DEVCMD_TIMEOUT); 50262306a36Sopenharmony_ci memcpy_fromio(comp, &ionic->idev.dev_cmd_regs->comp.vf_getattr, 50362306a36Sopenharmony_ci sizeof(*comp)); 50462306a36Sopenharmony_ci mutex_unlock(&ionic->dev_cmd_lock); 50562306a36Sopenharmony_ci 50662306a36Sopenharmony_ci if (err && comp->status != IONIC_RC_ENOSUPP) 50762306a36Sopenharmony_ci ionic_dev_cmd_dev_err_print(ionic, cmd.vf_getattr.opcode, 50862306a36Sopenharmony_ci comp->status, err); 50962306a36Sopenharmony_ci 51062306a36Sopenharmony_ci return err; 51162306a36Sopenharmony_ci} 51262306a36Sopenharmony_ci 51362306a36Sopenharmony_civoid ionic_vf_start(struct ionic *ionic) 51462306a36Sopenharmony_ci{ 51562306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 51662306a36Sopenharmony_ci .vf_ctrl.opcode = IONIC_CMD_VF_CTRL, 51762306a36Sopenharmony_ci .vf_ctrl.ctrl_opcode = IONIC_VF_CTRL_START_ALL, 51862306a36Sopenharmony_ci }; 51962306a36Sopenharmony_ci 52062306a36Sopenharmony_ci if (!(ionic->ident.dev.capabilities & cpu_to_le64(IONIC_DEV_CAP_VF_CTRL))) 52162306a36Sopenharmony_ci return; 52262306a36Sopenharmony_ci 52362306a36Sopenharmony_ci ionic_dev_cmd_go(&ionic->idev, &cmd); 52462306a36Sopenharmony_ci ionic_dev_cmd_wait(ionic, DEVCMD_TIMEOUT); 52562306a36Sopenharmony_ci} 52662306a36Sopenharmony_ci 52762306a36Sopenharmony_ci/* LIF commands */ 52862306a36Sopenharmony_civoid ionic_dev_cmd_queue_identify(struct ionic_dev *idev, 52962306a36Sopenharmony_ci u16 lif_type, u8 qtype, u8 qver) 53062306a36Sopenharmony_ci{ 53162306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 53262306a36Sopenharmony_ci .q_identify.opcode = IONIC_CMD_Q_IDENTIFY, 53362306a36Sopenharmony_ci .q_identify.lif_type = cpu_to_le16(lif_type), 53462306a36Sopenharmony_ci .q_identify.type = qtype, 53562306a36Sopenharmony_ci .q_identify.ver = qver, 53662306a36Sopenharmony_ci }; 53762306a36Sopenharmony_ci 53862306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 53962306a36Sopenharmony_ci} 54062306a36Sopenharmony_ci 54162306a36Sopenharmony_civoid ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver) 54262306a36Sopenharmony_ci{ 54362306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 54462306a36Sopenharmony_ci .lif_identify.opcode = IONIC_CMD_LIF_IDENTIFY, 54562306a36Sopenharmony_ci .lif_identify.type = type, 54662306a36Sopenharmony_ci .lif_identify.ver = ver, 54762306a36Sopenharmony_ci }; 54862306a36Sopenharmony_ci 54962306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 55062306a36Sopenharmony_ci} 55162306a36Sopenharmony_ci 55262306a36Sopenharmony_civoid ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index, 55362306a36Sopenharmony_ci dma_addr_t info_pa) 55462306a36Sopenharmony_ci{ 55562306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 55662306a36Sopenharmony_ci .lif_init.opcode = IONIC_CMD_LIF_INIT, 55762306a36Sopenharmony_ci .lif_init.index = cpu_to_le16(lif_index), 55862306a36Sopenharmony_ci .lif_init.info_pa = cpu_to_le64(info_pa), 55962306a36Sopenharmony_ci }; 56062306a36Sopenharmony_ci 56162306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 56262306a36Sopenharmony_ci} 56362306a36Sopenharmony_ci 56462306a36Sopenharmony_civoid ionic_dev_cmd_lif_reset(struct ionic_dev *idev, u16 lif_index) 56562306a36Sopenharmony_ci{ 56662306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 56762306a36Sopenharmony_ci .lif_init.opcode = IONIC_CMD_LIF_RESET, 56862306a36Sopenharmony_ci .lif_init.index = cpu_to_le16(lif_index), 56962306a36Sopenharmony_ci }; 57062306a36Sopenharmony_ci 57162306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 57262306a36Sopenharmony_ci} 57362306a36Sopenharmony_ci 57462306a36Sopenharmony_civoid ionic_dev_cmd_adminq_init(struct ionic_dev *idev, struct ionic_qcq *qcq, 57562306a36Sopenharmony_ci u16 lif_index, u16 intr_index) 57662306a36Sopenharmony_ci{ 57762306a36Sopenharmony_ci struct ionic_queue *q = &qcq->q; 57862306a36Sopenharmony_ci struct ionic_cq *cq = &qcq->cq; 57962306a36Sopenharmony_ci 58062306a36Sopenharmony_ci union ionic_dev_cmd cmd = { 58162306a36Sopenharmony_ci .q_init.opcode = IONIC_CMD_Q_INIT, 58262306a36Sopenharmony_ci .q_init.lif_index = cpu_to_le16(lif_index), 58362306a36Sopenharmony_ci .q_init.type = q->type, 58462306a36Sopenharmony_ci .q_init.ver = qcq->q.lif->qtype_info[q->type].version, 58562306a36Sopenharmony_ci .q_init.index = cpu_to_le32(q->index), 58662306a36Sopenharmony_ci .q_init.flags = cpu_to_le16(IONIC_QINIT_F_IRQ | 58762306a36Sopenharmony_ci IONIC_QINIT_F_ENA), 58862306a36Sopenharmony_ci .q_init.pid = cpu_to_le16(q->pid), 58962306a36Sopenharmony_ci .q_init.intr_index = cpu_to_le16(intr_index), 59062306a36Sopenharmony_ci .q_init.ring_size = ilog2(q->num_descs), 59162306a36Sopenharmony_ci .q_init.ring_base = cpu_to_le64(q->base_pa), 59262306a36Sopenharmony_ci .q_init.cq_ring_base = cpu_to_le64(cq->base_pa), 59362306a36Sopenharmony_ci }; 59462306a36Sopenharmony_ci 59562306a36Sopenharmony_ci ionic_dev_cmd_go(idev, &cmd); 59662306a36Sopenharmony_ci} 59762306a36Sopenharmony_ci 59862306a36Sopenharmony_ciint ionic_db_page_num(struct ionic_lif *lif, int pid) 59962306a36Sopenharmony_ci{ 60062306a36Sopenharmony_ci return (lif->hw_index * lif->dbid_count) + pid; 60162306a36Sopenharmony_ci} 60262306a36Sopenharmony_ci 60362306a36Sopenharmony_ciint ionic_get_cmb(struct ionic_lif *lif, u32 *pgid, phys_addr_t *pgaddr, int order) 60462306a36Sopenharmony_ci{ 60562306a36Sopenharmony_ci struct ionic_dev *idev = &lif->ionic->idev; 60662306a36Sopenharmony_ci int ret; 60762306a36Sopenharmony_ci 60862306a36Sopenharmony_ci mutex_lock(&idev->cmb_inuse_lock); 60962306a36Sopenharmony_ci ret = bitmap_find_free_region(idev->cmb_inuse, idev->cmb_npages, order); 61062306a36Sopenharmony_ci mutex_unlock(&idev->cmb_inuse_lock); 61162306a36Sopenharmony_ci 61262306a36Sopenharmony_ci if (ret < 0) 61362306a36Sopenharmony_ci return ret; 61462306a36Sopenharmony_ci 61562306a36Sopenharmony_ci *pgid = ret; 61662306a36Sopenharmony_ci *pgaddr = idev->phy_cmb_pages + ret * PAGE_SIZE; 61762306a36Sopenharmony_ci 61862306a36Sopenharmony_ci return 0; 61962306a36Sopenharmony_ci} 62062306a36Sopenharmony_ci 62162306a36Sopenharmony_civoid ionic_put_cmb(struct ionic_lif *lif, u32 pgid, int order) 62262306a36Sopenharmony_ci{ 62362306a36Sopenharmony_ci struct ionic_dev *idev = &lif->ionic->idev; 62462306a36Sopenharmony_ci 62562306a36Sopenharmony_ci mutex_lock(&idev->cmb_inuse_lock); 62662306a36Sopenharmony_ci bitmap_release_region(idev->cmb_inuse, pgid, order); 62762306a36Sopenharmony_ci mutex_unlock(&idev->cmb_inuse_lock); 62862306a36Sopenharmony_ci} 62962306a36Sopenharmony_ci 63062306a36Sopenharmony_ciint ionic_cq_init(struct ionic_lif *lif, struct ionic_cq *cq, 63162306a36Sopenharmony_ci struct ionic_intr_info *intr, 63262306a36Sopenharmony_ci unsigned int num_descs, size_t desc_size) 63362306a36Sopenharmony_ci{ 63462306a36Sopenharmony_ci unsigned int ring_size; 63562306a36Sopenharmony_ci 63662306a36Sopenharmony_ci if (desc_size == 0 || !is_power_of_2(num_descs)) 63762306a36Sopenharmony_ci return -EINVAL; 63862306a36Sopenharmony_ci 63962306a36Sopenharmony_ci ring_size = ilog2(num_descs); 64062306a36Sopenharmony_ci if (ring_size < 2 || ring_size > 16) 64162306a36Sopenharmony_ci return -EINVAL; 64262306a36Sopenharmony_ci 64362306a36Sopenharmony_ci cq->lif = lif; 64462306a36Sopenharmony_ci cq->bound_intr = intr; 64562306a36Sopenharmony_ci cq->num_descs = num_descs; 64662306a36Sopenharmony_ci cq->desc_size = desc_size; 64762306a36Sopenharmony_ci cq->tail_idx = 0; 64862306a36Sopenharmony_ci cq->done_color = 1; 64962306a36Sopenharmony_ci 65062306a36Sopenharmony_ci return 0; 65162306a36Sopenharmony_ci} 65262306a36Sopenharmony_ci 65362306a36Sopenharmony_civoid ionic_cq_map(struct ionic_cq *cq, void *base, dma_addr_t base_pa) 65462306a36Sopenharmony_ci{ 65562306a36Sopenharmony_ci struct ionic_cq_info *cur; 65662306a36Sopenharmony_ci unsigned int i; 65762306a36Sopenharmony_ci 65862306a36Sopenharmony_ci cq->base = base; 65962306a36Sopenharmony_ci cq->base_pa = base_pa; 66062306a36Sopenharmony_ci 66162306a36Sopenharmony_ci for (i = 0, cur = cq->info; i < cq->num_descs; i++, cur++) 66262306a36Sopenharmony_ci cur->cq_desc = base + (i * cq->desc_size); 66362306a36Sopenharmony_ci} 66462306a36Sopenharmony_ci 66562306a36Sopenharmony_civoid ionic_cq_bind(struct ionic_cq *cq, struct ionic_queue *q) 66662306a36Sopenharmony_ci{ 66762306a36Sopenharmony_ci cq->bound_q = q; 66862306a36Sopenharmony_ci} 66962306a36Sopenharmony_ci 67062306a36Sopenharmony_ciunsigned int ionic_cq_service(struct ionic_cq *cq, unsigned int work_to_do, 67162306a36Sopenharmony_ci ionic_cq_cb cb, ionic_cq_done_cb done_cb, 67262306a36Sopenharmony_ci void *done_arg) 67362306a36Sopenharmony_ci{ 67462306a36Sopenharmony_ci struct ionic_cq_info *cq_info; 67562306a36Sopenharmony_ci unsigned int work_done = 0; 67662306a36Sopenharmony_ci 67762306a36Sopenharmony_ci if (work_to_do == 0) 67862306a36Sopenharmony_ci return 0; 67962306a36Sopenharmony_ci 68062306a36Sopenharmony_ci cq_info = &cq->info[cq->tail_idx]; 68162306a36Sopenharmony_ci while (cb(cq, cq_info)) { 68262306a36Sopenharmony_ci if (cq->tail_idx == cq->num_descs - 1) 68362306a36Sopenharmony_ci cq->done_color = !cq->done_color; 68462306a36Sopenharmony_ci cq->tail_idx = (cq->tail_idx + 1) & (cq->num_descs - 1); 68562306a36Sopenharmony_ci cq_info = &cq->info[cq->tail_idx]; 68662306a36Sopenharmony_ci 68762306a36Sopenharmony_ci if (++work_done >= work_to_do) 68862306a36Sopenharmony_ci break; 68962306a36Sopenharmony_ci } 69062306a36Sopenharmony_ci 69162306a36Sopenharmony_ci if (work_done && done_cb) 69262306a36Sopenharmony_ci done_cb(done_arg); 69362306a36Sopenharmony_ci 69462306a36Sopenharmony_ci return work_done; 69562306a36Sopenharmony_ci} 69662306a36Sopenharmony_ci 69762306a36Sopenharmony_ciint ionic_q_init(struct ionic_lif *lif, struct ionic_dev *idev, 69862306a36Sopenharmony_ci struct ionic_queue *q, unsigned int index, const char *name, 69962306a36Sopenharmony_ci unsigned int num_descs, size_t desc_size, 70062306a36Sopenharmony_ci size_t sg_desc_size, unsigned int pid) 70162306a36Sopenharmony_ci{ 70262306a36Sopenharmony_ci unsigned int ring_size; 70362306a36Sopenharmony_ci 70462306a36Sopenharmony_ci if (desc_size == 0 || !is_power_of_2(num_descs)) 70562306a36Sopenharmony_ci return -EINVAL; 70662306a36Sopenharmony_ci 70762306a36Sopenharmony_ci ring_size = ilog2(num_descs); 70862306a36Sopenharmony_ci if (ring_size < 2 || ring_size > 16) 70962306a36Sopenharmony_ci return -EINVAL; 71062306a36Sopenharmony_ci 71162306a36Sopenharmony_ci q->lif = lif; 71262306a36Sopenharmony_ci q->idev = idev; 71362306a36Sopenharmony_ci q->index = index; 71462306a36Sopenharmony_ci q->num_descs = num_descs; 71562306a36Sopenharmony_ci q->desc_size = desc_size; 71662306a36Sopenharmony_ci q->sg_desc_size = sg_desc_size; 71762306a36Sopenharmony_ci q->tail_idx = 0; 71862306a36Sopenharmony_ci q->head_idx = 0; 71962306a36Sopenharmony_ci q->pid = pid; 72062306a36Sopenharmony_ci 72162306a36Sopenharmony_ci snprintf(q->name, sizeof(q->name), "L%d-%s%u", lif->index, name, index); 72262306a36Sopenharmony_ci 72362306a36Sopenharmony_ci return 0; 72462306a36Sopenharmony_ci} 72562306a36Sopenharmony_ci 72662306a36Sopenharmony_civoid ionic_q_map(struct ionic_queue *q, void *base, dma_addr_t base_pa) 72762306a36Sopenharmony_ci{ 72862306a36Sopenharmony_ci struct ionic_desc_info *cur; 72962306a36Sopenharmony_ci unsigned int i; 73062306a36Sopenharmony_ci 73162306a36Sopenharmony_ci q->base = base; 73262306a36Sopenharmony_ci q->base_pa = base_pa; 73362306a36Sopenharmony_ci 73462306a36Sopenharmony_ci for (i = 0, cur = q->info; i < q->num_descs; i++, cur++) 73562306a36Sopenharmony_ci cur->desc = base + (i * q->desc_size); 73662306a36Sopenharmony_ci} 73762306a36Sopenharmony_ci 73862306a36Sopenharmony_civoid ionic_q_cmb_map(struct ionic_queue *q, void __iomem *base, dma_addr_t base_pa) 73962306a36Sopenharmony_ci{ 74062306a36Sopenharmony_ci struct ionic_desc_info *cur; 74162306a36Sopenharmony_ci unsigned int i; 74262306a36Sopenharmony_ci 74362306a36Sopenharmony_ci q->cmb_base = base; 74462306a36Sopenharmony_ci q->cmb_base_pa = base_pa; 74562306a36Sopenharmony_ci 74662306a36Sopenharmony_ci for (i = 0, cur = q->info; i < q->num_descs; i++, cur++) 74762306a36Sopenharmony_ci cur->cmb_desc = base + (i * q->desc_size); 74862306a36Sopenharmony_ci} 74962306a36Sopenharmony_ci 75062306a36Sopenharmony_civoid ionic_q_sg_map(struct ionic_queue *q, void *base, dma_addr_t base_pa) 75162306a36Sopenharmony_ci{ 75262306a36Sopenharmony_ci struct ionic_desc_info *cur; 75362306a36Sopenharmony_ci unsigned int i; 75462306a36Sopenharmony_ci 75562306a36Sopenharmony_ci q->sg_base = base; 75662306a36Sopenharmony_ci q->sg_base_pa = base_pa; 75762306a36Sopenharmony_ci 75862306a36Sopenharmony_ci for (i = 0, cur = q->info; i < q->num_descs; i++, cur++) 75962306a36Sopenharmony_ci cur->sg_desc = base + (i * q->sg_desc_size); 76062306a36Sopenharmony_ci} 76162306a36Sopenharmony_ci 76262306a36Sopenharmony_civoid ionic_q_post(struct ionic_queue *q, bool ring_doorbell, ionic_desc_cb cb, 76362306a36Sopenharmony_ci void *cb_arg) 76462306a36Sopenharmony_ci{ 76562306a36Sopenharmony_ci struct ionic_desc_info *desc_info; 76662306a36Sopenharmony_ci struct ionic_lif *lif = q->lif; 76762306a36Sopenharmony_ci struct device *dev = q->dev; 76862306a36Sopenharmony_ci 76962306a36Sopenharmony_ci desc_info = &q->info[q->head_idx]; 77062306a36Sopenharmony_ci desc_info->cb = cb; 77162306a36Sopenharmony_ci desc_info->cb_arg = cb_arg; 77262306a36Sopenharmony_ci 77362306a36Sopenharmony_ci q->head_idx = (q->head_idx + 1) & (q->num_descs - 1); 77462306a36Sopenharmony_ci 77562306a36Sopenharmony_ci dev_dbg(dev, "lif=%d qname=%s qid=%d qtype=%d p_index=%d ringdb=%d\n", 77662306a36Sopenharmony_ci q->lif->index, q->name, q->hw_type, q->hw_index, 77762306a36Sopenharmony_ci q->head_idx, ring_doorbell); 77862306a36Sopenharmony_ci 77962306a36Sopenharmony_ci if (ring_doorbell) { 78062306a36Sopenharmony_ci ionic_dbell_ring(lif->kern_dbpage, q->hw_type, 78162306a36Sopenharmony_ci q->dbval | q->head_idx); 78262306a36Sopenharmony_ci 78362306a36Sopenharmony_ci q->dbell_jiffies = jiffies; 78462306a36Sopenharmony_ci 78562306a36Sopenharmony_ci if (q_to_qcq(q)->napi_qcq) 78662306a36Sopenharmony_ci mod_timer(&q_to_qcq(q)->napi_qcq->napi_deadline, 78762306a36Sopenharmony_ci jiffies + IONIC_NAPI_DEADLINE); 78862306a36Sopenharmony_ci } 78962306a36Sopenharmony_ci} 79062306a36Sopenharmony_ci 79162306a36Sopenharmony_cistatic bool ionic_q_is_posted(struct ionic_queue *q, unsigned int pos) 79262306a36Sopenharmony_ci{ 79362306a36Sopenharmony_ci unsigned int mask, tail, head; 79462306a36Sopenharmony_ci 79562306a36Sopenharmony_ci mask = q->num_descs - 1; 79662306a36Sopenharmony_ci tail = q->tail_idx; 79762306a36Sopenharmony_ci head = q->head_idx; 79862306a36Sopenharmony_ci 79962306a36Sopenharmony_ci return ((pos - tail) & mask) < ((head - tail) & mask); 80062306a36Sopenharmony_ci} 80162306a36Sopenharmony_ci 80262306a36Sopenharmony_civoid ionic_q_service(struct ionic_queue *q, struct ionic_cq_info *cq_info, 80362306a36Sopenharmony_ci unsigned int stop_index) 80462306a36Sopenharmony_ci{ 80562306a36Sopenharmony_ci struct ionic_desc_info *desc_info; 80662306a36Sopenharmony_ci ionic_desc_cb cb; 80762306a36Sopenharmony_ci void *cb_arg; 80862306a36Sopenharmony_ci u16 index; 80962306a36Sopenharmony_ci 81062306a36Sopenharmony_ci /* check for empty queue */ 81162306a36Sopenharmony_ci if (q->tail_idx == q->head_idx) 81262306a36Sopenharmony_ci return; 81362306a36Sopenharmony_ci 81462306a36Sopenharmony_ci /* stop index must be for a descriptor that is not yet completed */ 81562306a36Sopenharmony_ci if (unlikely(!ionic_q_is_posted(q, stop_index))) 81662306a36Sopenharmony_ci dev_err(q->dev, 81762306a36Sopenharmony_ci "ionic stop is not posted %s stop %u tail %u head %u\n", 81862306a36Sopenharmony_ci q->name, stop_index, q->tail_idx, q->head_idx); 81962306a36Sopenharmony_ci 82062306a36Sopenharmony_ci do { 82162306a36Sopenharmony_ci desc_info = &q->info[q->tail_idx]; 82262306a36Sopenharmony_ci index = q->tail_idx; 82362306a36Sopenharmony_ci q->tail_idx = (q->tail_idx + 1) & (q->num_descs - 1); 82462306a36Sopenharmony_ci 82562306a36Sopenharmony_ci cb = desc_info->cb; 82662306a36Sopenharmony_ci cb_arg = desc_info->cb_arg; 82762306a36Sopenharmony_ci 82862306a36Sopenharmony_ci desc_info->cb = NULL; 82962306a36Sopenharmony_ci desc_info->cb_arg = NULL; 83062306a36Sopenharmony_ci 83162306a36Sopenharmony_ci if (cb) 83262306a36Sopenharmony_ci cb(q, desc_info, cq_info, cb_arg); 83362306a36Sopenharmony_ci } while (index != stop_index); 83462306a36Sopenharmony_ci} 835