|
|
|
|
@ -1,11 +1,77 @@
|
|
|
|
|
#include "qlcnic.h"
|
|
|
|
|
#include "qlcnic_hw.h"
|
|
|
|
|
|
|
|
|
|
/* Reset template definitions */
|
|
|
|
|
#define QLC_83XX_RESTART_TEMPLATE_SIZE 0x2000
|
|
|
|
|
#define QLC_83XX_RESET_TEMPLATE_ADDR 0x4F0000
|
|
|
|
|
#define QLC_83XX_RESET_SEQ_VERSION 0x0101
|
|
|
|
|
|
|
|
|
|
#define QLC_83XX_OPCODE_NOP 0x0000
|
|
|
|
|
#define QLC_83XX_OPCODE_WRITE_LIST 0x0001
|
|
|
|
|
#define QLC_83XX_OPCODE_READ_WRITE_LIST 0x0002
|
|
|
|
|
#define QLC_83XX_OPCODE_POLL_LIST 0x0004
|
|
|
|
|
#define QLC_83XX_OPCODE_POLL_WRITE_LIST 0x0008
|
|
|
|
|
#define QLC_83XX_OPCODE_READ_MODIFY_WRITE 0x0010
|
|
|
|
|
#define QLC_83XX_OPCODE_SEQ_PAUSE 0x0020
|
|
|
|
|
#define QLC_83XX_OPCODE_SEQ_END 0x0040
|
|
|
|
|
#define QLC_83XX_OPCODE_TMPL_END 0x0080
|
|
|
|
|
#define QLC_83XX_OPCODE_POLL_READ_LIST 0x0100
|
|
|
|
|
|
|
|
|
|
static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter);
|
|
|
|
|
static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
|
|
|
|
|
static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev);
|
|
|
|
|
static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter);
|
|
|
|
|
|
|
|
|
|
/* Template header */
|
|
|
|
|
struct qlc_83xx_reset_hdr {
|
|
|
|
|
u16 version;
|
|
|
|
|
u16 signature;
|
|
|
|
|
u16 size;
|
|
|
|
|
u16 entries;
|
|
|
|
|
u16 hdr_size;
|
|
|
|
|
u16 checksum;
|
|
|
|
|
u16 init_offset;
|
|
|
|
|
u16 start_offset;
|
|
|
|
|
} __packed;
|
|
|
|
|
|
|
|
|
|
/* Command entry header. */
|
|
|
|
|
struct qlc_83xx_entry_hdr {
|
|
|
|
|
u16 cmd;
|
|
|
|
|
u16 size;
|
|
|
|
|
u16 count;
|
|
|
|
|
u16 delay;
|
|
|
|
|
} __packed;
|
|
|
|
|
|
|
|
|
|
/* Generic poll command */
|
|
|
|
|
struct qlc_83xx_poll {
|
|
|
|
|
u32 mask;
|
|
|
|
|
u32 status;
|
|
|
|
|
} __packed;
|
|
|
|
|
|
|
|
|
|
/* Read modify write command */
|
|
|
|
|
struct qlc_83xx_rmw {
|
|
|
|
|
u32 mask;
|
|
|
|
|
u32 xor_value;
|
|
|
|
|
u32 or_value;
|
|
|
|
|
u8 shl;
|
|
|
|
|
u8 shr;
|
|
|
|
|
u8 index_a;
|
|
|
|
|
u8 rsvd;
|
|
|
|
|
} __packed;
|
|
|
|
|
|
|
|
|
|
/* Generic command with 2 DWORD */
|
|
|
|
|
struct qlc_83xx_entry {
|
|
|
|
|
u32 arg1;
|
|
|
|
|
u32 arg2;
|
|
|
|
|
} __packed;
|
|
|
|
|
|
|
|
|
|
/* Generic command with 4 DWORD */
|
|
|
|
|
struct qlc_83xx_quad_entry {
|
|
|
|
|
u32 dr_addr;
|
|
|
|
|
u32 dr_value;
|
|
|
|
|
u32 ar_addr;
|
|
|
|
|
u32 ar_value;
|
|
|
|
|
} __packed;
|
|
|
|
|
static const char *const qlc_83xx_idc_states[] = {
|
|
|
|
|
"Unknown",
|
|
|
|
|
"Cold",
|
|
|
|
|
@ -961,8 +1027,13 @@ qlcnic_83xx_idc_first_to_load_function_handler(struct qlcnic_adapter *adapter)
|
|
|
|
|
|
|
|
|
|
static int qlcnic_83xx_idc_init(struct qlcnic_adapter *adapter)
|
|
|
|
|
{
|
|
|
|
|
int ret = -EIO;
|
|
|
|
|
|
|
|
|
|
qlcnic_83xx_setup_idc_parameters(adapter);
|
|
|
|
|
|
|
|
|
|
if (qlcnic_83xx_get_reset_instruction_template(adapter))
|
|
|
|
|
return ret;
|
|
|
|
|
|
|
|
|
|
if (!qlcnic_83xx_idc_check_driver_presence_reg(adapter)) {
|
|
|
|
|
if (qlcnic_83xx_idc_first_to_load_function_handler(adapter))
|
|
|
|
|
return -EIO;
|
|
|
|
|
@ -1190,6 +1261,7 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
|
|
|
|
|
val, val1);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
static void qlcnic_83xx_disable_pause_frames(struct qlcnic_adapter *adapter)
|
|
|
|
|
{
|
|
|
|
|
u32 reg = 0, i, j;
|
|
|
|
|
@ -1305,6 +1377,409 @@ int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)
|
|
|
|
|
return err;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr,
|
|
|
|
|
int duration, u32 mask, u32 status)
|
|
|
|
|
{
|
|
|
|
|
u32 value;
|
|
|
|
|
int timeout_error;
|
|
|
|
|
u8 retries;
|
|
|
|
|
|
|
|
|
|
value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
|
|
|
|
|
retries = duration / 10;
|
|
|
|
|
|
|
|
|
|
do {
|
|
|
|
|
if ((value & mask) != status) {
|
|
|
|
|
timeout_error = 1;
|
|
|
|
|
msleep(duration / 10);
|
|
|
|
|
value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
|
|
|
|
|
} else {
|
|
|
|
|
timeout_error = 0;
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
} while (retries--);
|
|
|
|
|
|
|
|
|
|
if (timeout_error) {
|
|
|
|
|
p_dev->ahw->reset.seq_error++;
|
|
|
|
|
dev_err(&p_dev->pdev->dev,
|
|
|
|
|
"%s: Timeout Err, entry_num = %d\n",
|
|
|
|
|
__func__, p_dev->ahw->reset.seq_index);
|
|
|
|
|
dev_err(&p_dev->pdev->dev,
|
|
|
|
|
"0x%08x 0x%08x 0x%08x\n",
|
|
|
|
|
value, mask, status);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return timeout_error;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter *p_dev)
|
|
|
|
|
{
|
|
|
|
|
u32 sum = 0;
|
|
|
|
|
u16 *buff = (u16 *)p_dev->ahw->reset.buff;
|
|
|
|
|
int count = p_dev->ahw->reset.hdr->size / sizeof(u16);
|
|
|
|
|
|
|
|
|
|
while (count-- > 0)
|
|
|
|
|
sum += *buff++;
|
|
|
|
|
|
|
|
|
|
while (sum >> 16)
|
|
|
|
|
sum = (sum & 0xFFFF) + (sum >> 16);
|
|
|
|
|
|
|
|
|
|
if (~sum) {
|
|
|
|
|
return 0;
|
|
|
|
|
} else {
|
|
|
|
|
dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
|
|
|
|
|
return -1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
|
|
|
|
|
{
|
|
|
|
|
u8 *p_buff;
|
|
|
|
|
u32 addr, count;
|
|
|
|
|
struct qlcnic_hardware_context *ahw = p_dev->ahw;
|
|
|
|
|
|
|
|
|
|
ahw->reset.seq_error = 0;
|
|
|
|
|
ahw->reset.buff = kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL);
|
|
|
|
|
|
|
|
|
|
if (p_dev->ahw->reset.buff == NULL) {
|
|
|
|
|
dev_err(&p_dev->pdev->dev,
|
|
|
|
|
"%s: resource allocation failed\n", __func__);
|
|
|
|
|
return -ENOMEM;
|
|
|
|
|
}
|
|
|
|
|
p_buff = p_dev->ahw->reset.buff;
|
|
|
|
|
addr = QLC_83XX_RESET_TEMPLATE_ADDR;
|
|
|
|
|
count = sizeof(struct qlc_83xx_reset_hdr) / sizeof(u32);
|
|
|
|
|
|
|
|
|
|
/* Copy template header from flash */
|
|
|
|
|
if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
|
|
|
|
|
dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
|
|
|
|
|
return -EIO;
|
|
|
|
|
}
|
|
|
|
|
ahw->reset.hdr = (struct qlc_83xx_reset_hdr *)ahw->reset.buff;
|
|
|
|
|
addr = QLC_83XX_RESET_TEMPLATE_ADDR + ahw->reset.hdr->hdr_size;
|
|
|
|
|
p_buff = ahw->reset.buff + ahw->reset.hdr->hdr_size;
|
|
|
|
|
count = (ahw->reset.hdr->size - ahw->reset.hdr->hdr_size) / sizeof(u32);
|
|
|
|
|
|
|
|
|
|
/* Copy rest of the template */
|
|
|
|
|
if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
|
|
|
|
|
dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
|
|
|
|
|
return -EIO;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (qlcnic_83xx_reset_template_checksum(p_dev))
|
|
|
|
|
return -EIO;
|
|
|
|
|
/* Get Stop, Start and Init command offsets */
|
|
|
|
|
ahw->reset.init_offset = ahw->reset.buff + ahw->reset.hdr->init_offset;
|
|
|
|
|
ahw->reset.start_offset = ahw->reset.buff +
|
|
|
|
|
ahw->reset.hdr->start_offset;
|
|
|
|
|
ahw->reset.stop_offset = ahw->reset.buff + ahw->reset.hdr->hdr_size;
|
|
|
|
|
return 0;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read Write HW register command */
|
|
|
|
|
static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev,
|
|
|
|
|
u32 raddr, u32 waddr)
|
|
|
|
|
{
|
|
|
|
|
int value;
|
|
|
|
|
|
|
|
|
|
value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
|
|
|
|
|
qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read Modify Write HW register command */
|
|
|
|
|
static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev,
|
|
|
|
|
u32 raddr, u32 waddr,
|
|
|
|
|
struct qlc_83xx_rmw *p_rmw_hdr)
|
|
|
|
|
{
|
|
|
|
|
int value;
|
|
|
|
|
|
|
|
|
|
if (p_rmw_hdr->index_a)
|
|
|
|
|
value = p_dev->ahw->reset.array[p_rmw_hdr->index_a];
|
|
|
|
|
else
|
|
|
|
|
value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
|
|
|
|
|
|
|
|
|
|
value &= p_rmw_hdr->mask;
|
|
|
|
|
value <<= p_rmw_hdr->shl;
|
|
|
|
|
value >>= p_rmw_hdr->shr;
|
|
|
|
|
value |= p_rmw_hdr->or_value;
|
|
|
|
|
value ^= p_rmw_hdr->xor_value;
|
|
|
|
|
qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Write HW register command */
|
|
|
|
|
static void qlcnic_83xx_write_list(struct qlcnic_adapter *p_dev,
|
|
|
|
|
struct qlc_83xx_entry_hdr *p_hdr)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
struct qlc_83xx_entry *entry;
|
|
|
|
|
|
|
|
|
|
entry = (struct qlc_83xx_entry *)((char *)p_hdr +
|
|
|
|
|
sizeof(struct qlc_83xx_entry_hdr));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < p_hdr->count; i++, entry++) {
|
|
|
|
|
qlcnic_83xx_wrt_reg_indirect(p_dev, entry->arg1,
|
|
|
|
|
entry->arg2);
|
|
|
|
|
if (p_hdr->delay)
|
|
|
|
|
udelay((u32)(p_hdr->delay));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read and Write instruction */
|
|
|
|
|
static void qlcnic_83xx_read_write_list(struct qlcnic_adapter *p_dev,
|
|
|
|
|
struct qlc_83xx_entry_hdr *p_hdr)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
struct qlc_83xx_entry *entry;
|
|
|
|
|
|
|
|
|
|
entry = (struct qlc_83xx_entry *)((char *)p_hdr +
|
|
|
|
|
sizeof(struct qlc_83xx_entry_hdr));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < p_hdr->count; i++, entry++) {
|
|
|
|
|
qlcnic_83xx_read_write_crb_reg(p_dev, entry->arg1,
|
|
|
|
|
entry->arg2);
|
|
|
|
|
if (p_hdr->delay)
|
|
|
|
|
udelay((u32)(p_hdr->delay));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Poll HW register command */
|
|
|
|
|
static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
|
|
|
|
|
struct qlc_83xx_entry_hdr *p_hdr)
|
|
|
|
|
{
|
|
|
|
|
long delay;
|
|
|
|
|
struct qlc_83xx_entry *entry;
|
|
|
|
|
struct qlc_83xx_poll *poll;
|
|
|
|
|
int i;
|
|
|
|
|
unsigned long arg1, arg2;
|
|
|
|
|
|
|
|
|
|
poll = (struct qlc_83xx_poll *)((char *)p_hdr +
|
|
|
|
|
sizeof(struct qlc_83xx_entry_hdr));
|
|
|
|
|
|
|
|
|
|
entry = (struct qlc_83xx_entry *)((char *)poll +
|
|
|
|
|
sizeof(struct qlc_83xx_poll));
|
|
|
|
|
delay = (long)p_hdr->delay;
|
|
|
|
|
|
|
|
|
|
if (!delay) {
|
|
|
|
|
for (i = 0; i < p_hdr->count; i++, entry++)
|
|
|
|
|
qlcnic_83xx_poll_reg(p_dev, entry->arg1,
|
|
|
|
|
delay, poll->mask,
|
|
|
|
|
poll->status);
|
|
|
|
|
} else {
|
|
|
|
|
for (i = 0; i < p_hdr->count; i++, entry++) {
|
|
|
|
|
arg1 = entry->arg1;
|
|
|
|
|
arg2 = entry->arg2;
|
|
|
|
|
if (delay) {
|
|
|
|
|
if (qlcnic_83xx_poll_reg(p_dev,
|
|
|
|
|
arg1, delay,
|
|
|
|
|
poll->mask,
|
|
|
|
|
poll->status)){
|
|
|
|
|
qlcnic_83xx_rd_reg_indirect(p_dev,
|
|
|
|
|
arg1);
|
|
|
|
|
qlcnic_83xx_rd_reg_indirect(p_dev,
|
|
|
|
|
arg2);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Poll and write HW register command */
|
|
|
|
|
static void qlcnic_83xx_poll_write_list(struct qlcnic_adapter *p_dev,
|
|
|
|
|
struct qlc_83xx_entry_hdr *p_hdr)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
long delay;
|
|
|
|
|
struct qlc_83xx_quad_entry *entry;
|
|
|
|
|
struct qlc_83xx_poll *poll;
|
|
|
|
|
|
|
|
|
|
poll = (struct qlc_83xx_poll *)((char *)p_hdr +
|
|
|
|
|
sizeof(struct qlc_83xx_entry_hdr));
|
|
|
|
|
entry = (struct qlc_83xx_quad_entry *)((char *)poll +
|
|
|
|
|
sizeof(struct qlc_83xx_poll));
|
|
|
|
|
delay = (long)p_hdr->delay;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < p_hdr->count; i++, entry++) {
|
|
|
|
|
qlcnic_83xx_wrt_reg_indirect(p_dev, entry->dr_addr,
|
|
|
|
|
entry->dr_value);
|
|
|
|
|
qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
|
|
|
|
|
entry->ar_value);
|
|
|
|
|
if (delay)
|
|
|
|
|
qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
|
|
|
|
|
poll->mask, poll->status);
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read Modify Write register command */
|
|
|
|
|
static void qlcnic_83xx_read_modify_write(struct qlcnic_adapter *p_dev,
|
|
|
|
|
struct qlc_83xx_entry_hdr *p_hdr)
|
|
|
|
|
{
|
|
|
|
|
int i;
|
|
|
|
|
struct qlc_83xx_entry *entry;
|
|
|
|
|
struct qlc_83xx_rmw *rmw_hdr;
|
|
|
|
|
|
|
|
|
|
rmw_hdr = (struct qlc_83xx_rmw *)((char *)p_hdr +
|
|
|
|
|
sizeof(struct qlc_83xx_entry_hdr));
|
|
|
|
|
|
|
|
|
|
entry = (struct qlc_83xx_entry *)((char *)rmw_hdr +
|
|
|
|
|
sizeof(struct qlc_83xx_rmw));
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < p_hdr->count; i++, entry++) {
|
|
|
|
|
qlcnic_83xx_rmw_crb_reg(p_dev, entry->arg1,
|
|
|
|
|
entry->arg2, rmw_hdr);
|
|
|
|
|
if (p_hdr->delay)
|
|
|
|
|
udelay((u32)(p_hdr->delay));
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void qlcnic_83xx_pause(struct qlc_83xx_entry_hdr *p_hdr)
|
|
|
|
|
{
|
|
|
|
|
if (p_hdr->delay)
|
|
|
|
|
mdelay((u32)((long)p_hdr->delay));
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* Read and poll register command */
|
|
|
|
|
static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
|
|
|
|
|
struct qlc_83xx_entry_hdr *p_hdr)
|
|
|
|
|
{
|
|
|
|
|
long delay;
|
|
|
|
|
int index, i, j;
|
|
|
|
|
struct qlc_83xx_quad_entry *entry;
|
|
|
|
|
struct qlc_83xx_poll *poll;
|
|
|
|
|
unsigned long addr;
|
|
|
|
|
|
|
|
|
|
poll = (struct qlc_83xx_poll *)((char *)p_hdr +
|
|
|
|
|
sizeof(struct qlc_83xx_entry_hdr));
|
|
|
|
|
|
|
|
|
|
entry = (struct qlc_83xx_quad_entry *)((char *)poll +
|
|
|
|
|
sizeof(struct qlc_83xx_poll));
|
|
|
|
|
delay = (long)p_hdr->delay;
|
|
|
|
|
|
|
|
|
|
for (i = 0; i < p_hdr->count; i++, entry++) {
|
|
|
|
|
qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
|
|
|
|
|
entry->ar_value);
|
|
|
|
|
if (delay) {
|
|
|
|
|
if (!qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
|
|
|
|
|
poll->mask, poll->status)){
|
|
|
|
|
index = p_dev->ahw->reset.array_index;
|
|
|
|
|
addr = entry->dr_addr;
|
|
|
|
|
j = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
|
|
|
|
|
p_dev->ahw->reset.array[index++] = j;
|
|
|
|
|
|
|
|
|
|
if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES)
|
|
|
|
|
p_dev->ahw->reset.array_index = 1;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static inline void qlcnic_83xx_seq_end(struct qlcnic_adapter *p_dev)
|
|
|
|
|
{
|
|
|
|
|
p_dev->ahw->reset.seq_end = 1;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void qlcnic_83xx_template_end(struct qlcnic_adapter *p_dev)
|
|
|
|
|
{
|
|
|
|
|
p_dev->ahw->reset.template_end = 1;
|
|
|
|
|
if (p_dev->ahw->reset.seq_error == 0)
|
|
|
|
|
dev_err(&p_dev->pdev->dev,
|
|
|
|
|
"HW restart process completed successfully.\n");
|
|
|
|
|
else
|
|
|
|
|
dev_err(&p_dev->pdev->dev,
|
|
|
|
|
"HW restart completed with timeout errors.\n");
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* qlcnic_83xx_exec_template_cmd
|
|
|
|
|
*
|
|
|
|
|
* @p_dev: adapter structure
|
|
|
|
|
* @p_buff: Poiter to instruction template
|
|
|
|
|
*
|
|
|
|
|
* Template provides instructions to stop, restart and initalize firmware.
|
|
|
|
|
* These instructions are abstracted as a series of read, write and
|
|
|
|
|
* poll operations on hardware registers. Register information and operation
|
|
|
|
|
* specifics are not exposed to the driver. Driver reads the template from
|
|
|
|
|
* flash and executes the instructions located at pre-defined offsets.
|
|
|
|
|
*
|
|
|
|
|
* Returns: None
|
|
|
|
|
* */
|
|
|
|
|
static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev,
|
|
|
|
|
char *p_buff)
|
|
|
|
|
{
|
|
|
|
|
int index, entries;
|
|
|
|
|
struct qlc_83xx_entry_hdr *p_hdr;
|
|
|
|
|
char *entry = p_buff;
|
|
|
|
|
|
|
|
|
|
p_dev->ahw->reset.seq_end = 0;
|
|
|
|
|
p_dev->ahw->reset.template_end = 0;
|
|
|
|
|
entries = p_dev->ahw->reset.hdr->entries;
|
|
|
|
|
index = p_dev->ahw->reset.seq_index;
|
|
|
|
|
|
|
|
|
|
for (; (!p_dev->ahw->reset.seq_end) && (index < entries); index++) {
|
|
|
|
|
p_hdr = (struct qlc_83xx_entry_hdr *)entry;
|
|
|
|
|
|
|
|
|
|
switch (p_hdr->cmd) {
|
|
|
|
|
case QLC_83XX_OPCODE_NOP:
|
|
|
|
|
break;
|
|
|
|
|
case QLC_83XX_OPCODE_WRITE_LIST:
|
|
|
|
|
qlcnic_83xx_write_list(p_dev, p_hdr);
|
|
|
|
|
break;
|
|
|
|
|
case QLC_83XX_OPCODE_READ_WRITE_LIST:
|
|
|
|
|
qlcnic_83xx_read_write_list(p_dev, p_hdr);
|
|
|
|
|
break;
|
|
|
|
|
case QLC_83XX_OPCODE_POLL_LIST:
|
|
|
|
|
qlcnic_83xx_poll_list(p_dev, p_hdr);
|
|
|
|
|
break;
|
|
|
|
|
case QLC_83XX_OPCODE_POLL_WRITE_LIST:
|
|
|
|
|
qlcnic_83xx_poll_write_list(p_dev, p_hdr);
|
|
|
|
|
break;
|
|
|
|
|
case QLC_83XX_OPCODE_READ_MODIFY_WRITE:
|
|
|
|
|
qlcnic_83xx_read_modify_write(p_dev, p_hdr);
|
|
|
|
|
break;
|
|
|
|
|
case QLC_83XX_OPCODE_SEQ_PAUSE:
|
|
|
|
|
qlcnic_83xx_pause(p_hdr);
|
|
|
|
|
break;
|
|
|
|
|
case QLC_83XX_OPCODE_SEQ_END:
|
|
|
|
|
qlcnic_83xx_seq_end(p_dev);
|
|
|
|
|
break;
|
|
|
|
|
case QLC_83XX_OPCODE_TMPL_END:
|
|
|
|
|
qlcnic_83xx_template_end(p_dev);
|
|
|
|
|
break;
|
|
|
|
|
case QLC_83XX_OPCODE_POLL_READ_LIST:
|
|
|
|
|
qlcnic_83xx_poll_read_list(p_dev, p_hdr);
|
|
|
|
|
break;
|
|
|
|
|
default:
|
|
|
|
|
dev_err(&p_dev->pdev->dev,
|
|
|
|
|
"%s: Unknown opcode 0x%04x in template %d\n",
|
|
|
|
|
__func__, p_hdr->cmd, index);
|
|
|
|
|
break;
|
|
|
|
|
}
|
|
|
|
|
entry += p_hdr->size;
|
|
|
|
|
}
|
|
|
|
|
p_dev->ahw->reset.seq_index = index;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev)
|
|
|
|
|
{
|
|
|
|
|
p_dev->ahw->reset.seq_index = 0;
|
|
|
|
|
|
|
|
|
|
qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.stop_offset);
|
|
|
|
|
if (p_dev->ahw->reset.seq_end != 1)
|
|
|
|
|
dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void qlcnic_83xx_start_hw(struct qlcnic_adapter *p_dev)
|
|
|
|
|
{
|
|
|
|
|
qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.start_offset);
|
|
|
|
|
if (p_dev->ahw->reset.template_end != 1)
|
|
|
|
|
dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static void qlcnic_83xx_init_hw(struct qlcnic_adapter *p_dev)
|
|
|
|
|
{
|
|
|
|
|
qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.init_offset);
|
|
|
|
|
if (p_dev->ahw->reset.seq_end != 1)
|
|
|
|
|
dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
static int qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter)
|
|
|
|
|
{
|
|
|
|
|
int err = -EIO;
|
|
|
|
|
@ -1329,6 +1804,9 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
|
|
|
|
|
{
|
|
|
|
|
int err = -EIO;
|
|
|
|
|
|
|
|
|
|
qlcnic_83xx_stop_hw(adapter);
|
|
|
|
|
qlcnic_83xx_init_hw(adapter);
|
|
|
|
|
|
|
|
|
|
if (qlcnic_83xx_copy_bootloader(adapter))
|
|
|
|
|
return err;
|
|
|
|
|
/* Boot either flash image or firmware image from host file system */
|
|
|
|
|
@ -1340,6 +1818,7 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
|
|
|
|
|
QLC_83XX_BOOT_FROM_FLASH);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
qlcnic_83xx_start_hw(adapter);
|
|
|
|
|
if (qlcnic_83xx_check_hw_status(adapter))
|
|
|
|
|
return -EIO;
|
|
|
|
|
|
|
|
|
|
|