269 lines
6.2 KiB
C
269 lines
6.2 KiB
C
// SPDX-License-Identifier: GPL-2.0
|
|
/* Copyright(c) 2017 - 2019 Pensando Systems, Inc */
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/types.h>
|
|
#include <linux/errno.h>
|
|
#include <linux/io.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/etherdevice.h>
|
|
#include "ionic.h"
|
|
#include "ionic_dev.h"
|
|
#include "ionic_lif.h"
|
|
|
|
void ionic_init_devinfo(struct ionic *ionic)
|
|
{
|
|
struct ionic_dev *idev = &ionic->idev;
|
|
|
|
idev->dev_info.asic_type = ioread8(&idev->dev_info_regs->asic_type);
|
|
idev->dev_info.asic_rev = ioread8(&idev->dev_info_regs->asic_rev);
|
|
|
|
memcpy_fromio(idev->dev_info.fw_version,
|
|
idev->dev_info_regs->fw_version,
|
|
IONIC_DEVINFO_FWVERS_BUFLEN);
|
|
|
|
memcpy_fromio(idev->dev_info.serial_num,
|
|
idev->dev_info_regs->serial_num,
|
|
IONIC_DEVINFO_SERIAL_BUFLEN);
|
|
|
|
idev->dev_info.fw_version[IONIC_DEVINFO_FWVERS_BUFLEN] = 0;
|
|
idev->dev_info.serial_num[IONIC_DEVINFO_SERIAL_BUFLEN] = 0;
|
|
|
|
dev_dbg(ionic->dev, "fw_version %s\n", idev->dev_info.fw_version);
|
|
}
|
|
|
|
int ionic_dev_setup(struct ionic *ionic)
|
|
{
|
|
struct ionic_dev_bar *bar = ionic->bars;
|
|
unsigned int num_bars = ionic->num_bars;
|
|
struct ionic_dev *idev = &ionic->idev;
|
|
struct device *dev = ionic->dev;
|
|
u32 sig;
|
|
|
|
/* BAR0: dev_cmd and interrupts */
|
|
if (num_bars < 1) {
|
|
dev_err(dev, "No bars found, aborting\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
if (bar->len < IONIC_BAR0_SIZE) {
|
|
dev_err(dev, "Resource bar size %lu too small, aborting\n",
|
|
bar->len);
|
|
return -EFAULT;
|
|
}
|
|
|
|
idev->dev_info_regs = bar->vaddr + IONIC_BAR0_DEV_INFO_REGS_OFFSET;
|
|
idev->dev_cmd_regs = bar->vaddr + IONIC_BAR0_DEV_CMD_REGS_OFFSET;
|
|
idev->intr_status = bar->vaddr + IONIC_BAR0_INTR_STATUS_OFFSET;
|
|
idev->intr_ctrl = bar->vaddr + IONIC_BAR0_INTR_CTRL_OFFSET;
|
|
|
|
sig = ioread32(&idev->dev_info_regs->signature);
|
|
if (sig != IONIC_DEV_INFO_SIGNATURE) {
|
|
dev_err(dev, "Incompatible firmware signature %x", sig);
|
|
return -EFAULT;
|
|
}
|
|
|
|
ionic_init_devinfo(ionic);
|
|
|
|
/* BAR1: doorbells */
|
|
bar++;
|
|
if (num_bars < 2) {
|
|
dev_err(dev, "Doorbell bar missing, aborting\n");
|
|
return -EFAULT;
|
|
}
|
|
|
|
idev->db_pages = bar->vaddr;
|
|
idev->phy_db_pages = bar->bus_addr;
|
|
|
|
return 0;
|
|
}
|
|
|
|
void ionic_dev_teardown(struct ionic *ionic)
|
|
{
|
|
/* place holder */
|
|
}
|
|
|
|
/* Devcmd Interface */
|
|
u8 ionic_dev_cmd_status(struct ionic_dev *idev)
|
|
{
|
|
return ioread8(&idev->dev_cmd_regs->comp.comp.status);
|
|
}
|
|
|
|
bool ionic_dev_cmd_done(struct ionic_dev *idev)
|
|
{
|
|
return ioread32(&idev->dev_cmd_regs->done) & IONIC_DEV_CMD_DONE;
|
|
}
|
|
|
|
void ionic_dev_cmd_comp(struct ionic_dev *idev, union ionic_dev_cmd_comp *comp)
|
|
{
|
|
memcpy_fromio(comp, &idev->dev_cmd_regs->comp, sizeof(*comp));
|
|
}
|
|
|
|
void ionic_dev_cmd_go(struct ionic_dev *idev, union ionic_dev_cmd *cmd)
|
|
{
|
|
memcpy_toio(&idev->dev_cmd_regs->cmd, cmd, sizeof(*cmd));
|
|
iowrite32(0, &idev->dev_cmd_regs->done);
|
|
iowrite32(1, &idev->dev_cmd_regs->doorbell);
|
|
}
|
|
|
|
/* Device commands */
|
|
void ionic_dev_cmd_identify(struct ionic_dev *idev, u8 ver)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.identify.opcode = IONIC_CMD_IDENTIFY,
|
|
.identify.ver = ver,
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_init(struct ionic_dev *idev)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.init.opcode = IONIC_CMD_INIT,
|
|
.init.type = 0,
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_reset(struct ionic_dev *idev)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.reset.opcode = IONIC_CMD_RESET,
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
/* Port commands */
|
|
void ionic_dev_cmd_port_identify(struct ionic_dev *idev)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.port_init.opcode = IONIC_CMD_PORT_IDENTIFY,
|
|
.port_init.index = 0,
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_port_init(struct ionic_dev *idev)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.port_init.opcode = IONIC_CMD_PORT_INIT,
|
|
.port_init.index = 0,
|
|
.port_init.info_pa = cpu_to_le64(idev->port_info_pa),
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_port_reset(struct ionic_dev *idev)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.port_reset.opcode = IONIC_CMD_PORT_RESET,
|
|
.port_reset.index = 0,
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_port_state(struct ionic_dev *idev, u8 state)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
|
|
.port_setattr.index = 0,
|
|
.port_setattr.attr = IONIC_PORT_ATTR_STATE,
|
|
.port_setattr.state = state,
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_port_speed(struct ionic_dev *idev, u32 speed)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
|
|
.port_setattr.index = 0,
|
|
.port_setattr.attr = IONIC_PORT_ATTR_SPEED,
|
|
.port_setattr.speed = cpu_to_le32(speed),
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_port_autoneg(struct ionic_dev *idev, u8 an_enable)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
|
|
.port_setattr.index = 0,
|
|
.port_setattr.attr = IONIC_PORT_ATTR_AUTONEG,
|
|
.port_setattr.an_enable = an_enable,
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_port_fec(struct ionic_dev *idev, u8 fec_type)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
|
|
.port_setattr.index = 0,
|
|
.port_setattr.attr = IONIC_PORT_ATTR_FEC,
|
|
.port_setattr.fec_type = fec_type,
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_port_pause(struct ionic_dev *idev, u8 pause_type)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.port_setattr.opcode = IONIC_CMD_PORT_SETATTR,
|
|
.port_setattr.index = 0,
|
|
.port_setattr.attr = IONIC_PORT_ATTR_PAUSE,
|
|
.port_setattr.pause_type = pause_type,
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
/* LIF commands */
|
|
void ionic_dev_cmd_lif_identify(struct ionic_dev *idev, u8 type, u8 ver)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.lif_identify.opcode = IONIC_CMD_LIF_IDENTIFY,
|
|
.lif_identify.type = type,
|
|
.lif_identify.ver = ver,
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_lif_init(struct ionic_dev *idev, u16 lif_index,
|
|
dma_addr_t info_pa)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.lif_init.opcode = IONIC_CMD_LIF_INIT,
|
|
.lif_init.index = cpu_to_le16(lif_index),
|
|
.lif_init.info_pa = cpu_to_le64(info_pa),
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
void ionic_dev_cmd_lif_reset(struct ionic_dev *idev, u16 lif_index)
|
|
{
|
|
union ionic_dev_cmd cmd = {
|
|
.lif_init.opcode = IONIC_CMD_LIF_RESET,
|
|
.lif_init.index = cpu_to_le16(lif_index),
|
|
};
|
|
|
|
ionic_dev_cmd_go(idev, &cmd);
|
|
}
|
|
|
|
int ionic_db_page_num(struct ionic_lif *lif, int pid)
|
|
{
|
|
return (lif->hw_index * lif->dbid_count) + pid;
|
|
}
|