aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic.h1
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c40
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h17
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c479
-rw-r--r--drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c1
5 files changed, 538 insertions, 0 deletions
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 9a6d093441fa..5b36d92b237d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -442,6 +442,7 @@ struct qlcnic_hardware_context {
442 struct qlcnic_nic_intr_coalesce coal; 442 struct qlcnic_nic_intr_coalesce coal;
443 struct qlcnic_fw_dump fw_dump; 443 struct qlcnic_fw_dump fw_dump;
444 struct qlcnic_fdt fdt; 444 struct qlcnic_fdt fdt;
445 struct qlc_83xx_reset reset;
445 struct qlc_83xx_idc idc; 446 struct qlc_83xx_idc idc;
446 struct qlc_83xx_fw_info fw_info; 447 struct qlc_83xx_fw_info fw_info;
447 struct qlcnic_intrpt_config *intr_tbl; 448 struct qlcnic_intrpt_config *intr_tbl;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
index 8fdc4e681028..9cd51cbaecbc 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.c
@@ -2343,3 +2343,43 @@ int qlcnic_83xx_ms_mem_write128(struct qlcnic_adapter *adapter, u64 addr,
2343 2343
2344 return ret; 2344 return ret;
2345} 2345}
2346
2347int qlcnic_83xx_flash_read32(struct qlcnic_adapter *adapter, u32 flash_addr,
2348 u8 *p_data, int count)
2349{
2350 int i, ret;
2351 u32 word, addr = flash_addr;
2352 ulong indirect_addr;
2353
2354 if (qlcnic_83xx_lock_flash(adapter) != 0)
2355 return -EIO;
2356
2357 if (addr & 0x3) {
2358 dev_err(&adapter->pdev->dev, "Illegal addr = 0x%x\n", addr);
2359 qlcnic_83xx_unlock_flash(adapter);
2360 return -EIO;
2361 }
2362
2363 for (i = 0; i < count; i++) {
2364 if (qlcnic_83xx_wrt_reg_indirect(adapter,
2365 QLC_83XX_FLASH_DIRECT_WINDOW,
2366 (addr))) {
2367 qlcnic_83xx_unlock_flash(adapter);
2368 return -EIO;
2369 }
2370
2371 indirect_addr = QLC_83XX_FLASH_DIRECT_DATA(addr);
2372 ret = qlcnic_83xx_rd_reg_indirect(adapter,
2373 indirect_addr);
2374 if (ret == -EIO)
2375 return -EIO;
2376 word = ret;
2377 *p_data = word;
2378 p_data = p_data + 4;
2379 addr = addr + 4;
2380 }
2381
2382 qlcnic_83xx_unlock_flash(adapter);
2383
2384 return 0;
2385}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
index 99b84277b86f..969bda8e32c4 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_hw.h
@@ -77,6 +77,8 @@
77#define QLC_83XX_BOOT_FROM_FLASH 0 77#define QLC_83XX_BOOT_FROM_FLASH 0
78#define QLC_83XX_BOOT_FROM_FILE 0x12345678 78#define QLC_83XX_BOOT_FROM_FILE 0x12345678
79 79
80#define QLC_83XX_MAX_RESET_SEQ_ENTRIES 16
81
80struct qlcnic_intrpt_config { 82struct qlcnic_intrpt_config {
81 u8 type; 83 u8 type;
82 u8 enabled; 84 u8 enabled;
@@ -98,6 +100,20 @@ struct qlc_83xx_fw_info {
98 u8 load_from_file; 100 u8 load_from_file;
99}; 101};
100 102
103struct qlc_83xx_reset {
104 struct qlc_83xx_reset_hdr *hdr;
105 int seq_index;
106 int seq_error;
107 int array_index;
108 u32 array[QLC_83XX_MAX_RESET_SEQ_ENTRIES];
109 u8 *buff;
110 u8 *stop_offset;
111 u8 *start_offset;
112 u8 *init_offset;
113 u8 seq_end;
114 u8 template_end;
115};
116
101#define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY 0x1 117#define QLC_83XX_IDC_DISABLE_FW_RESET_RECOVERY 0x1
102#define QLC_83XX_IDC_GRACEFULL_RESET 0x2 118#define QLC_83XX_IDC_GRACEFULL_RESET 0x2
103#define QLC_83XX_IDC_TIMESTAMP 0 119#define QLC_83XX_IDC_TIMESTAMP 0
@@ -377,6 +393,7 @@ int qlcnic_83xx_init(struct qlcnic_adapter *);
377int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *); 393int qlcnic_83xx_idc_ready_state_entry(struct qlcnic_adapter *);
378int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev); 394int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev);
379void qlcnic_83xx_idc_poll_dev_state(struct work_struct *); 395void qlcnic_83xx_idc_poll_dev_state(struct work_struct *);
396int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *);
380void qlcnic_83xx_idc_exit(struct qlcnic_adapter *); 397void qlcnic_83xx_idc_exit(struct qlcnic_adapter *);
381void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *, u32); 398void qlcnic_83xx_idc_request_reset(struct qlcnic_adapter *, u32);
382int qlcnic_83xx_lock_driver(struct qlcnic_adapter *); 399int qlcnic_83xx_lock_driver(struct qlcnic_adapter *);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
index c26d1901900a..d222ee291e7c 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_83xx_init.c
@@ -1,11 +1,77 @@
1#include "qlcnic.h" 1#include "qlcnic.h"
2#include "qlcnic_hw.h" 2#include "qlcnic_hw.h"
3 3
4/* Reset template definitions */
5#define QLC_83XX_RESTART_TEMPLATE_SIZE 0x2000
6#define QLC_83XX_RESET_TEMPLATE_ADDR 0x4F0000
7#define QLC_83XX_RESET_SEQ_VERSION 0x0101
8
9#define QLC_83XX_OPCODE_NOP 0x0000
10#define QLC_83XX_OPCODE_WRITE_LIST 0x0001
11#define QLC_83XX_OPCODE_READ_WRITE_LIST 0x0002
12#define QLC_83XX_OPCODE_POLL_LIST 0x0004
13#define QLC_83XX_OPCODE_POLL_WRITE_LIST 0x0008
14#define QLC_83XX_OPCODE_READ_MODIFY_WRITE 0x0010
15#define QLC_83XX_OPCODE_SEQ_PAUSE 0x0020
16#define QLC_83XX_OPCODE_SEQ_END 0x0040
17#define QLC_83XX_OPCODE_TMPL_END 0x0080
18#define QLC_83XX_OPCODE_POLL_READ_LIST 0x0100
19
4static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter); 20static int qlcnic_83xx_init_default_driver(struct qlcnic_adapter *adapter);
5static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter); 21static int qlcnic_83xx_configure_opmode(struct qlcnic_adapter *adapter);
6static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev); 22static int qlcnic_83xx_check_heartbeat(struct qlcnic_adapter *p_dev);
7static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter); 23static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter);
8 24
25/* Template header */
26struct qlc_83xx_reset_hdr {
27 u16 version;
28 u16 signature;
29 u16 size;
30 u16 entries;
31 u16 hdr_size;
32 u16 checksum;
33 u16 init_offset;
34 u16 start_offset;
35} __packed;
36
37/* Command entry header. */
38struct qlc_83xx_entry_hdr {
39 u16 cmd;
40 u16 size;
41 u16 count;
42 u16 delay;
43} __packed;
44
45/* Generic poll command */
46struct qlc_83xx_poll {
47 u32 mask;
48 u32 status;
49} __packed;
50
51/* Read modify write command */
52struct qlc_83xx_rmw {
53 u32 mask;
54 u32 xor_value;
55 u32 or_value;
56 u8 shl;
57 u8 shr;
58 u8 index_a;
59 u8 rsvd;
60} __packed;
61
62/* Generic command with 2 DWORD */
63struct qlc_83xx_entry {
64 u32 arg1;
65 u32 arg2;
66} __packed;
67
68/* Generic command with 4 DWORD */
69struct qlc_83xx_quad_entry {
70 u32 dr_addr;
71 u32 dr_value;
72 u32 ar_addr;
73 u32 ar_value;
74} __packed;
9static const char *const qlc_83xx_idc_states[] = { 75static const char *const qlc_83xx_idc_states[] = {
10 "Unknown", 76 "Unknown",
11 "Cold", 77 "Cold",
@@ -961,8 +1027,13 @@ qlcnic_83xx_idc_first_to_load_function_handler(struct qlcnic_adapter *adapter)
961 1027
962static int qlcnic_83xx_idc_init(struct qlcnic_adapter *adapter) 1028static int qlcnic_83xx_idc_init(struct qlcnic_adapter *adapter)
963{ 1029{
1030 int ret = -EIO;
1031
964 qlcnic_83xx_setup_idc_parameters(adapter); 1032 qlcnic_83xx_setup_idc_parameters(adapter);
965 1033
1034 if (qlcnic_83xx_get_reset_instruction_template(adapter))
1035 return ret;
1036
966 if (!qlcnic_83xx_idc_check_driver_presence_reg(adapter)) { 1037 if (!qlcnic_83xx_idc_check_driver_presence_reg(adapter)) {
967 if (qlcnic_83xx_idc_first_to_load_function_handler(adapter)) 1038 if (qlcnic_83xx_idc_first_to_load_function_handler(adapter))
968 return -EIO; 1039 return -EIO;
@@ -1190,6 +1261,7 @@ static void qlcnic_83xx_dump_pause_control_regs(struct qlcnic_adapter *adapter)
1190 val, val1); 1261 val, val1);
1191} 1262}
1192 1263
1264
1193static void qlcnic_83xx_disable_pause_frames(struct qlcnic_adapter *adapter) 1265static void qlcnic_83xx_disable_pause_frames(struct qlcnic_adapter *adapter)
1194{ 1266{
1195 u32 reg = 0, i, j; 1267 u32 reg = 0, i, j;
@@ -1305,6 +1377,409 @@ int qlcnic_83xx_check_hw_status(struct qlcnic_adapter *p_dev)
1305 return err; 1377 return err;
1306} 1378}
1307 1379
1380static int qlcnic_83xx_poll_reg(struct qlcnic_adapter *p_dev, u32 addr,
1381 int duration, u32 mask, u32 status)
1382{
1383 u32 value;
1384 int timeout_error;
1385 u8 retries;
1386
1387 value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
1388 retries = duration / 10;
1389
1390 do {
1391 if ((value & mask) != status) {
1392 timeout_error = 1;
1393 msleep(duration / 10);
1394 value = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
1395 } else {
1396 timeout_error = 0;
1397 break;
1398 }
1399 } while (retries--);
1400
1401 if (timeout_error) {
1402 p_dev->ahw->reset.seq_error++;
1403 dev_err(&p_dev->pdev->dev,
1404 "%s: Timeout Err, entry_num = %d\n",
1405 __func__, p_dev->ahw->reset.seq_index);
1406 dev_err(&p_dev->pdev->dev,
1407 "0x%08x 0x%08x 0x%08x\n",
1408 value, mask, status);
1409 }
1410
1411 return timeout_error;
1412}
1413
1414static int qlcnic_83xx_reset_template_checksum(struct qlcnic_adapter *p_dev)
1415{
1416 u32 sum = 0;
1417 u16 *buff = (u16 *)p_dev->ahw->reset.buff;
1418 int count = p_dev->ahw->reset.hdr->size / sizeof(u16);
1419
1420 while (count-- > 0)
1421 sum += *buff++;
1422
1423 while (sum >> 16)
1424 sum = (sum & 0xFFFF) + (sum >> 16);
1425
1426 if (~sum) {
1427 return 0;
1428 } else {
1429 dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
1430 return -1;
1431 }
1432}
1433
1434int qlcnic_83xx_get_reset_instruction_template(struct qlcnic_adapter *p_dev)
1435{
1436 u8 *p_buff;
1437 u32 addr, count;
1438 struct qlcnic_hardware_context *ahw = p_dev->ahw;
1439
1440 ahw->reset.seq_error = 0;
1441 ahw->reset.buff = kzalloc(QLC_83XX_RESTART_TEMPLATE_SIZE, GFP_KERNEL);
1442
1443 if (p_dev->ahw->reset.buff == NULL) {
1444 dev_err(&p_dev->pdev->dev,
1445 "%s: resource allocation failed\n", __func__);
1446 return -ENOMEM;
1447 }
1448 p_buff = p_dev->ahw->reset.buff;
1449 addr = QLC_83XX_RESET_TEMPLATE_ADDR;
1450 count = sizeof(struct qlc_83xx_reset_hdr) / sizeof(u32);
1451
1452 /* Copy template header from flash */
1453 if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
1454 dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
1455 return -EIO;
1456 }
1457 ahw->reset.hdr = (struct qlc_83xx_reset_hdr *)ahw->reset.buff;
1458 addr = QLC_83XX_RESET_TEMPLATE_ADDR + ahw->reset.hdr->hdr_size;
1459 p_buff = ahw->reset.buff + ahw->reset.hdr->hdr_size;
1460 count = (ahw->reset.hdr->size - ahw->reset.hdr->hdr_size) / sizeof(u32);
1461
1462 /* Copy rest of the template */
1463 if (qlcnic_83xx_flash_read32(p_dev, addr, p_buff, count)) {
1464 dev_err(&p_dev->pdev->dev, "%s: flash read failed\n", __func__);
1465 return -EIO;
1466 }
1467
1468 if (qlcnic_83xx_reset_template_checksum(p_dev))
1469 return -EIO;
1470 /* Get Stop, Start and Init command offsets */
1471 ahw->reset.init_offset = ahw->reset.buff + ahw->reset.hdr->init_offset;
1472 ahw->reset.start_offset = ahw->reset.buff +
1473 ahw->reset.hdr->start_offset;
1474 ahw->reset.stop_offset = ahw->reset.buff + ahw->reset.hdr->hdr_size;
1475 return 0;
1476}
1477
1478/* Read Write HW register command */
1479static void qlcnic_83xx_read_write_crb_reg(struct qlcnic_adapter *p_dev,
1480 u32 raddr, u32 waddr)
1481{
1482 int value;
1483
1484 value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
1485 qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
1486}
1487
1488/* Read Modify Write HW register command */
1489static void qlcnic_83xx_rmw_crb_reg(struct qlcnic_adapter *p_dev,
1490 u32 raddr, u32 waddr,
1491 struct qlc_83xx_rmw *p_rmw_hdr)
1492{
1493 int value;
1494
1495 if (p_rmw_hdr->index_a)
1496 value = p_dev->ahw->reset.array[p_rmw_hdr->index_a];
1497 else
1498 value = qlcnic_83xx_rd_reg_indirect(p_dev, raddr);
1499
1500 value &= p_rmw_hdr->mask;
1501 value <<= p_rmw_hdr->shl;
1502 value >>= p_rmw_hdr->shr;
1503 value |= p_rmw_hdr->or_value;
1504 value ^= p_rmw_hdr->xor_value;
1505 qlcnic_83xx_wrt_reg_indirect(p_dev, waddr, value);
1506}
1507
1508/* Write HW register command */
1509static void qlcnic_83xx_write_list(struct qlcnic_adapter *p_dev,
1510 struct qlc_83xx_entry_hdr *p_hdr)
1511{
1512 int i;
1513 struct qlc_83xx_entry *entry;
1514
1515 entry = (struct qlc_83xx_entry *)((char *)p_hdr +
1516 sizeof(struct qlc_83xx_entry_hdr));
1517
1518 for (i = 0; i < p_hdr->count; i++, entry++) {
1519 qlcnic_83xx_wrt_reg_indirect(p_dev, entry->arg1,
1520 entry->arg2);
1521 if (p_hdr->delay)
1522 udelay((u32)(p_hdr->delay));
1523 }
1524}
1525
1526/* Read and Write instruction */
1527static void qlcnic_83xx_read_write_list(struct qlcnic_adapter *p_dev,
1528 struct qlc_83xx_entry_hdr *p_hdr)
1529{
1530 int i;
1531 struct qlc_83xx_entry *entry;
1532
1533 entry = (struct qlc_83xx_entry *)((char *)p_hdr +
1534 sizeof(struct qlc_83xx_entry_hdr));
1535
1536 for (i = 0; i < p_hdr->count; i++, entry++) {
1537 qlcnic_83xx_read_write_crb_reg(p_dev, entry->arg1,
1538 entry->arg2);
1539 if (p_hdr->delay)
1540 udelay((u32)(p_hdr->delay));
1541 }
1542}
1543
1544/* Poll HW register command */
1545static void qlcnic_83xx_poll_list(struct qlcnic_adapter *p_dev,
1546 struct qlc_83xx_entry_hdr *p_hdr)
1547{
1548 long delay;
1549 struct qlc_83xx_entry *entry;
1550 struct qlc_83xx_poll *poll;
1551 int i;
1552 unsigned long arg1, arg2;
1553
1554 poll = (struct qlc_83xx_poll *)((char *)p_hdr +
1555 sizeof(struct qlc_83xx_entry_hdr));
1556
1557 entry = (struct qlc_83xx_entry *)((char *)poll +
1558 sizeof(struct qlc_83xx_poll));
1559 delay = (long)p_hdr->delay;
1560
1561 if (!delay) {
1562 for (i = 0; i < p_hdr->count; i++, entry++)
1563 qlcnic_83xx_poll_reg(p_dev, entry->arg1,
1564 delay, poll->mask,
1565 poll->status);
1566 } else {
1567 for (i = 0; i < p_hdr->count; i++, entry++) {
1568 arg1 = entry->arg1;
1569 arg2 = entry->arg2;
1570 if (delay) {
1571 if (qlcnic_83xx_poll_reg(p_dev,
1572 arg1, delay,
1573 poll->mask,
1574 poll->status)){
1575 qlcnic_83xx_rd_reg_indirect(p_dev,
1576 arg1);
1577 qlcnic_83xx_rd_reg_indirect(p_dev,
1578 arg2);
1579 }
1580 }
1581 }
1582 }
1583}
1584
1585/* Poll and write HW register command */
1586static void qlcnic_83xx_poll_write_list(struct qlcnic_adapter *p_dev,
1587 struct qlc_83xx_entry_hdr *p_hdr)
1588{
1589 int i;
1590 long delay;
1591 struct qlc_83xx_quad_entry *entry;
1592 struct qlc_83xx_poll *poll;
1593
1594 poll = (struct qlc_83xx_poll *)((char *)p_hdr +
1595 sizeof(struct qlc_83xx_entry_hdr));
1596 entry = (struct qlc_83xx_quad_entry *)((char *)poll +
1597 sizeof(struct qlc_83xx_poll));
1598 delay = (long)p_hdr->delay;
1599
1600 for (i = 0; i < p_hdr->count; i++, entry++) {
1601 qlcnic_83xx_wrt_reg_indirect(p_dev, entry->dr_addr,
1602 entry->dr_value);
1603 qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
1604 entry->ar_value);
1605 if (delay)
1606 qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
1607 poll->mask, poll->status);
1608 }
1609}
1610
1611/* Read Modify Write register command */
1612static void qlcnic_83xx_read_modify_write(struct qlcnic_adapter *p_dev,
1613 struct qlc_83xx_entry_hdr *p_hdr)
1614{
1615 int i;
1616 struct qlc_83xx_entry *entry;
1617 struct qlc_83xx_rmw *rmw_hdr;
1618
1619 rmw_hdr = (struct qlc_83xx_rmw *)((char *)p_hdr +
1620 sizeof(struct qlc_83xx_entry_hdr));
1621
1622 entry = (struct qlc_83xx_entry *)((char *)rmw_hdr +
1623 sizeof(struct qlc_83xx_rmw));
1624
1625 for (i = 0; i < p_hdr->count; i++, entry++) {
1626 qlcnic_83xx_rmw_crb_reg(p_dev, entry->arg1,
1627 entry->arg2, rmw_hdr);
1628 if (p_hdr->delay)
1629 udelay((u32)(p_hdr->delay));
1630 }
1631}
1632
1633static void qlcnic_83xx_pause(struct qlc_83xx_entry_hdr *p_hdr)
1634{
1635 if (p_hdr->delay)
1636 mdelay((u32)((long)p_hdr->delay));
1637}
1638
1639/* Read and poll register command */
1640static void qlcnic_83xx_poll_read_list(struct qlcnic_adapter *p_dev,
1641 struct qlc_83xx_entry_hdr *p_hdr)
1642{
1643 long delay;
1644 int index, i, j;
1645 struct qlc_83xx_quad_entry *entry;
1646 struct qlc_83xx_poll *poll;
1647 unsigned long addr;
1648
1649 poll = (struct qlc_83xx_poll *)((char *)p_hdr +
1650 sizeof(struct qlc_83xx_entry_hdr));
1651
1652 entry = (struct qlc_83xx_quad_entry *)((char *)poll +
1653 sizeof(struct qlc_83xx_poll));
1654 delay = (long)p_hdr->delay;
1655
1656 for (i = 0; i < p_hdr->count; i++, entry++) {
1657 qlcnic_83xx_wrt_reg_indirect(p_dev, entry->ar_addr,
1658 entry->ar_value);
1659 if (delay) {
1660 if (!qlcnic_83xx_poll_reg(p_dev, entry->ar_addr, delay,
1661 poll->mask, poll->status)){
1662 index = p_dev->ahw->reset.array_index;
1663 addr = entry->dr_addr;
1664 j = qlcnic_83xx_rd_reg_indirect(p_dev, addr);
1665 p_dev->ahw->reset.array[index++] = j;
1666
1667 if (index == QLC_83XX_MAX_RESET_SEQ_ENTRIES)
1668 p_dev->ahw->reset.array_index = 1;
1669 }
1670 }
1671 }
1672}
1673
1674static inline void qlcnic_83xx_seq_end(struct qlcnic_adapter *p_dev)
1675{
1676 p_dev->ahw->reset.seq_end = 1;
1677}
1678
1679static void qlcnic_83xx_template_end(struct qlcnic_adapter *p_dev)
1680{
1681 p_dev->ahw->reset.template_end = 1;
1682 if (p_dev->ahw->reset.seq_error == 0)
1683 dev_err(&p_dev->pdev->dev,
1684 "HW restart process completed successfully.\n");
1685 else
1686 dev_err(&p_dev->pdev->dev,
1687 "HW restart completed with timeout errors.\n");
1688}
1689
1690/**
1691* qlcnic_83xx_exec_template_cmd
1692*
1693* @p_dev: adapter structure
1694* @p_buff: Poiter to instruction template
1695*
1696* Template provides instructions to stop, restart and initalize firmware.
1697* These instructions are abstracted as a series of read, write and
1698* poll operations on hardware registers. Register information and operation
1699* specifics are not exposed to the driver. Driver reads the template from
1700* flash and executes the instructions located at pre-defined offsets.
1701*
1702* Returns: None
1703* */
1704static void qlcnic_83xx_exec_template_cmd(struct qlcnic_adapter *p_dev,
1705 char *p_buff)
1706{
1707 int index, entries;
1708 struct qlc_83xx_entry_hdr *p_hdr;
1709 char *entry = p_buff;
1710
1711 p_dev->ahw->reset.seq_end = 0;
1712 p_dev->ahw->reset.template_end = 0;
1713 entries = p_dev->ahw->reset.hdr->entries;
1714 index = p_dev->ahw->reset.seq_index;
1715
1716 for (; (!p_dev->ahw->reset.seq_end) && (index < entries); index++) {
1717 p_hdr = (struct qlc_83xx_entry_hdr *)entry;
1718
1719 switch (p_hdr->cmd) {
1720 case QLC_83XX_OPCODE_NOP:
1721 break;
1722 case QLC_83XX_OPCODE_WRITE_LIST:
1723 qlcnic_83xx_write_list(p_dev, p_hdr);
1724 break;
1725 case QLC_83XX_OPCODE_READ_WRITE_LIST:
1726 qlcnic_83xx_read_write_list(p_dev, p_hdr);
1727 break;
1728 case QLC_83XX_OPCODE_POLL_LIST:
1729 qlcnic_83xx_poll_list(p_dev, p_hdr);
1730 break;
1731 case QLC_83XX_OPCODE_POLL_WRITE_LIST:
1732 qlcnic_83xx_poll_write_list(p_dev, p_hdr);
1733 break;
1734 case QLC_83XX_OPCODE_READ_MODIFY_WRITE:
1735 qlcnic_83xx_read_modify_write(p_dev, p_hdr);
1736 break;
1737 case QLC_83XX_OPCODE_SEQ_PAUSE:
1738 qlcnic_83xx_pause(p_hdr);
1739 break;
1740 case QLC_83XX_OPCODE_SEQ_END:
1741 qlcnic_83xx_seq_end(p_dev);
1742 break;
1743 case QLC_83XX_OPCODE_TMPL_END:
1744 qlcnic_83xx_template_end(p_dev);
1745 break;
1746 case QLC_83XX_OPCODE_POLL_READ_LIST:
1747 qlcnic_83xx_poll_read_list(p_dev, p_hdr);
1748 break;
1749 default:
1750 dev_err(&p_dev->pdev->dev,
1751 "%s: Unknown opcode 0x%04x in template %d\n",
1752 __func__, p_hdr->cmd, index);
1753 break;
1754 }
1755 entry += p_hdr->size;
1756 }
1757 p_dev->ahw->reset.seq_index = index;
1758}
1759
1760static void qlcnic_83xx_stop_hw(struct qlcnic_adapter *p_dev)
1761{
1762 p_dev->ahw->reset.seq_index = 0;
1763
1764 qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.stop_offset);
1765 if (p_dev->ahw->reset.seq_end != 1)
1766 dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
1767}
1768
1769static void qlcnic_83xx_start_hw(struct qlcnic_adapter *p_dev)
1770{
1771 qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.start_offset);
1772 if (p_dev->ahw->reset.template_end != 1)
1773 dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
1774}
1775
1776static void qlcnic_83xx_init_hw(struct qlcnic_adapter *p_dev)
1777{
1778 qlcnic_83xx_exec_template_cmd(p_dev, p_dev->ahw->reset.init_offset);
1779 if (p_dev->ahw->reset.seq_end != 1)
1780 dev_err(&p_dev->pdev->dev, "%s: failed\n", __func__);
1781}
1782
1308static int qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter) 1783static int qlcnic_83xx_load_fw_image_from_host(struct qlcnic_adapter *adapter)
1309{ 1784{
1310 int err = -EIO; 1785 int err = -EIO;
@@ -1329,6 +1804,9 @@ static int qlcnic_83xx_restart_hw(struct qlcnic_adapter *adapter)
1329{ 1804{
1330 int err = -EIO; 1805 int err = -EIO;
1331 1806
1807 qlcnic_83xx_stop_hw(adapter);
1808 qlcnic_83xx_init_hw(adapter);
1809
1332 if (qlcnic_83xx_copy_bootloader(adapter)) 1810 if (qlcnic_83xx_copy_bootloader(adapter))
1333 return err; 1811 return err;
1334 /* Boot either flash image or firmware image from host file system */ 1812 /* 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)
1340 QLC_83XX_BOOT_FROM_FLASH); 1818 QLC_83XX_BOOT_FROM_FLASH);
1341 } 1819 }
1342 1820
1821 qlcnic_83xx_start_hw(adapter);
1343 if (qlcnic_83xx_check_hw_status(adapter)) 1822 if (qlcnic_83xx_check_hw_status(adapter))
1344 return -EIO; 1823 return -EIO;
1345 1824
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index c10670f6d1c8..c71e1dc7295d 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -1473,6 +1473,7 @@ static void qlcnic_free_adapter_resources(struct qlcnic_adapter *adapter)
1473 adapter->ahw->fw_dump.tmpl_hdr = NULL; 1473 adapter->ahw->fw_dump.tmpl_hdr = NULL;
1474 } 1474 }
1475 1475
1476 kfree(adapter->ahw->reset.buff);
1476 adapter->ahw->fw_dump.tmpl_hdr = NULL; 1477 adapter->ahw->fw_dump.tmpl_hdr = NULL;
1477} 1478}
1478 1479