#include "ena_hw.h"
#include "ena.h"
uint32_t
ena_hw_bar_read32(const ena_t *ena, const uint16_t offset)
{
caddr_t addr = ena->ena_reg_base + offset;
return (ena_hw_abs_read32(ena, (uint32_t *)addr));
}
uint32_t
ena_hw_abs_read32(const ena_t *ena, uint32_t *addr)
{
VERIFY3U(addr, >=, ena->ena_reg_base);
VERIFY3U(addr, <, ena->ena_reg_base + (ena->ena_reg_size - 4));
return (ddi_get32(ena->ena_reg_hdl, addr));
}
void
ena_hw_bar_write32(const ena_t *ena, const uint16_t offset, const uint32_t val)
{
caddr_t addr = ena->ena_reg_base + offset;
ena_hw_abs_write32(ena, (uint32_t *)addr, val);
}
void
ena_hw_abs_write32(const ena_t *ena, uint32_t *addr, const uint32_t val)
{
VERIFY3P(ena, !=, NULL);
VERIFY3P(addr, !=, NULL);
VERIFY3U(addr, >=, ena->ena_reg_base);
VERIFY3U(addr, <, ena->ena_reg_base + (ena->ena_reg_size - 4));
ddi_put32(ena->ena_reg_hdl, addr, val);
}
int
enahw_resp_status_to_errno(ena_t *ena, enahw_resp_status_t status)
{
int ret = 0;
switch (status) {
case ENAHW_RESP_SUCCESS:
break;
case ENAHW_RESP_RESOURCE_ALLOCATION_FAILURE:
ret = ENOMEM;
break;
case ENAHW_RESP_UNSUPPORTED_OPCODE:
ret = ENOTSUP;
break;
case ENAHW_RESP_BAD_OPCODE:
case ENAHW_RESP_MALFORMED_REQUEST:
case ENAHW_RESP_ILLEGAL_PARAMETER:
ret = EINVAL;
break;
case ENAHW_RESP_RESOURCE_BUSY:
ret = EAGAIN;
break;
case ENAHW_RESP_UNKNOWN_ERROR:
default:
ena_err(ena, "unexpected status code: %d", status);
ret = EIO;
break;
}
return (ret);
}
const char *
enahw_reset_reason(enahw_reset_reason_t reason)
{
switch (reason) {
case ENAHW_RESET_NORMAL:
return ("normal");
case ENAHW_RESET_KEEP_ALIVE_TO:
return ("keep-alive timeout");
case ENAHW_RESET_ADMIN_TO:
return ("admin timeout");
case ENAHW_RESET_MISS_TX_CMPL:
return ("missed TX completion");
case ENAHW_RESET_INV_RX_REQ_ID:
return ("invalid RX request ID");
case ENAHW_RESET_INV_TX_REQ_ID:
return ("invalid TX request ID");
case ENAHW_RESET_TOO_MANY_RX_DESCS:
return ("too many RX descs");
case ENAHW_RESET_INIT_ERR:
return ("initialization error");
case ENAHW_RESET_DRIVER_INVALID_STATE:
return ("invalid driver state");
case ENAHW_RESET_OS_TRIGGER:
return ("OS trigger");
case ENAHW_RESET_OS_NETDEV_WD:
return ("netdev watchdog");
case ENAHW_RESET_SHUTDOWN:
return ("shutdown");
case ENAHW_RESET_USER_TRIGGER:
return ("user trigger");
case ENAHW_RESET_GENERIC:
return ("generic");
case ENAHW_RESET_MISS_INTERRUPT:
return ("missed interrupt");
case ENAHW_RESET_SUSPECTED_POLL_STARVATION:
return ("suspected poll starvation");
case ENAHW_RESET_RX_DESCRIPTOR_MALFORMED:
return ("malformed RX descriptor");
case ENAHW_RESET_TX_DESCRIPTOR_MALFORMED:
return ("malformed TX descriptor");
case ENAHW_RESET_MISSING_ADMIN_INTERRUPT:
return ("missing admin interrupt");
case ENAHW_RESET_DEVICE_REQUEST:
return ("device request");
default:
return ("unknown");
}
}
#ifdef DEBUG
static const ena_reg_t reg_cache_template[ENAHW_NUM_REGS] = {
{
.er_name = "Version",
.er_offset = ENAHW_REG_VERSION
},
{
.er_name = "Controller Version",
.er_offset = ENAHW_REG_CONTROLLER_VERSION
},
{
.er_name = "Caps",
.er_offset = ENAHW_REG_CAPS
},
{
.er_name = "Extended Caps",
.er_offset = ENAHW_REG_CAPS_EXT
},
{
.er_name = "Admin SQ Base Low",
.er_offset = ENAHW_REG_ASQ_BASE_LO
},
{
.er_name = "Admin SQ Base High",
.er_offset = ENAHW_REG_ASQ_BASE_HI
},
{
.er_name = "Admin SQ Caps",
.er_offset = ENAHW_REG_ASQ_CAPS
},
{
.er_name = "Gap 0x1C",
.er_offset = ENAHW_REG_GAP_1C
},
{
.er_name = "Admin CQ Base Low",
.er_offset = ENAHW_REG_ACQ_BASE_LO
},
{
.er_name = "Admin CQ Base High",
.er_offset = ENAHW_REG_ACQ_BASE_HI
},
{
.er_name = "Admin CQ Caps",
.er_offset = ENAHW_REG_ACQ_CAPS
},
{
.er_name = "Admin SQ Doorbell",
.er_offset = ENAHW_REG_ASQ_DB
},
{
.er_name = "Admin CQ Tail",
.er_offset = ENAHW_REG_ACQ_TAIL
},
{
.er_name = "Admin Event Notification Queue Caps",
.er_offset = ENAHW_REG_AENQ_CAPS
},
{
.er_name = "Admin Event Notification Queue Base Low",
.er_offset = ENAHW_REG_AENQ_BASE_LO
},
{
.er_name = "Admin Event Notification Queue Base High",
.er_offset = ENAHW_REG_AENQ_BASE_HI
},
{
.er_name = "Admin Event Notification Queue Head Doorbell",
.er_offset = ENAHW_REG_AENQ_HEAD_DB
},
{
.er_name = "Admin Event Notification Queue Tail",
.er_offset = ENAHW_REG_AENQ_TAIL
},
{
.er_name = "Gap 0x48",
.er_offset = ENAHW_REG_GAP_48
},
{
.er_name = "Interrupt Mask (disable interrupts)",
.er_offset = ENAHW_REG_INTERRUPT_MASK
},
{
.er_name = "Gap 0x50",
.er_offset = ENAHW_REG_GAP_50
},
{
.er_name = "Device Control",
.er_offset = ENAHW_REG_DEV_CTL
},
{
.er_name = "Device Status",
.er_offset = ENAHW_REG_DEV_STS
},
{
.er_name = "MMIO Register Read",
.er_offset = ENAHW_REG_MMIO_REG_READ
},
{
.er_name = "MMIO Response Address Low",
.er_offset = ENAHW_REG_MMIO_RESP_LO
},
{
.er_name = "MMIO Response Address High",
.er_offset = ENAHW_REG_MMIO_RESP_HI
},
{
.er_name = "RSS Indirection Entry Update",
.er_offset = ENAHW_REG_RSS_IND_ENTRY_UPDATE
},
};
void
ena_update_regcache(ena_t *ena)
{
for (uint_t i = 0; i < ENAHW_NUM_REGS; i++) {
ena_reg_t *r = &ena->ena_reg[i];
r->er_value = ena_hw_bar_read32(ena, r->er_offset);
}
}
void
ena_init_regcache(ena_t *ena)
{
bcopy(reg_cache_template, ena->ena_reg, sizeof (ena->ena_reg));
ena_update_regcache(ena);
}
#endif