diff options
Diffstat (limited to 'drivers/net/qlge/qlge_mpi.c')
-rw-r--r-- | drivers/net/qlge/qlge_mpi.c | 165 |
1 files changed, 165 insertions, 0 deletions
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c index e2b2286102d4..e2c846f17fc7 100644 --- a/drivers/net/qlge/qlge_mpi.c +++ b/drivers/net/qlge/qlge_mpi.c | |||
@@ -1,5 +1,54 @@ | |||
1 | #include "qlge.h" | 1 | #include "qlge.h" |
2 | 2 | ||
3 | int ql_unpause_mpi_risc(struct ql_adapter *qdev) | ||
4 | { | ||
5 | u32 tmp; | ||
6 | |||
7 | /* Un-pause the RISC */ | ||
8 | tmp = ql_read32(qdev, CSR); | ||
9 | if (!(tmp & CSR_RP)) | ||
10 | return -EIO; | ||
11 | |||
12 | ql_write32(qdev, CSR, CSR_CMD_CLR_PAUSE); | ||
13 | return 0; | ||
14 | } | ||
15 | |||
16 | int ql_pause_mpi_risc(struct ql_adapter *qdev) | ||
17 | { | ||
18 | u32 tmp; | ||
19 | int count = UDELAY_COUNT; | ||
20 | |||
21 | /* Pause the RISC */ | ||
22 | ql_write32(qdev, CSR, CSR_CMD_SET_PAUSE); | ||
23 | do { | ||
24 | tmp = ql_read32(qdev, CSR); | ||
25 | if (tmp & CSR_RP) | ||
26 | break; | ||
27 | mdelay(UDELAY_DELAY); | ||
28 | count--; | ||
29 | } while (count); | ||
30 | return (count == 0) ? -ETIMEDOUT : 0; | ||
31 | } | ||
32 | |||
33 | int ql_hard_reset_mpi_risc(struct ql_adapter *qdev) | ||
34 | { | ||
35 | u32 tmp; | ||
36 | int count = UDELAY_COUNT; | ||
37 | |||
38 | /* Reset the RISC */ | ||
39 | ql_write32(qdev, CSR, CSR_CMD_SET_RST); | ||
40 | do { | ||
41 | tmp = ql_read32(qdev, CSR); | ||
42 | if (tmp & CSR_RR) { | ||
43 | ql_write32(qdev, CSR, CSR_CMD_CLR_RST); | ||
44 | break; | ||
45 | } | ||
46 | mdelay(UDELAY_DELAY); | ||
47 | count--; | ||
48 | } while (count); | ||
49 | return (count == 0) ? -ETIMEDOUT : 0; | ||
50 | } | ||
51 | |||
3 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data) | 52 | int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data) |
4 | { | 53 | { |
5 | int status; | 54 | int status; |
@@ -45,6 +94,35 @@ int ql_soft_reset_mpi_risc(struct ql_adapter *qdev) | |||
45 | return status; | 94 | return status; |
46 | } | 95 | } |
47 | 96 | ||
97 | /* Determine if we are in charge of the firwmare. If | ||
98 | * we are the lower of the 2 NIC pcie functions, or if | ||
99 | * we are the higher function and the lower function | ||
100 | * is not enabled. | ||
101 | */ | ||
102 | int ql_own_firmware(struct ql_adapter *qdev) | ||
103 | { | ||
104 | u32 temp; | ||
105 | |||
106 | /* If we are the lower of the 2 NIC functions | ||
107 | * on the chip the we are responsible for | ||
108 | * core dump and firmware reset after an error. | ||
109 | */ | ||
110 | if (qdev->func < qdev->alt_func) | ||
111 | return 1; | ||
112 | |||
113 | /* If we are the higher of the 2 NIC functions | ||
114 | * on the chip and the lower function is not | ||
115 | * enabled, then we are responsible for | ||
116 | * core dump and firmware reset after an error. | ||
117 | */ | ||
118 | temp = ql_read32(qdev, STS); | ||
119 | if (!(temp & (1 << (8 + qdev->alt_func)))) | ||
120 | return 1; | ||
121 | |||
122 | return 0; | ||
123 | |||
124 | } | ||
125 | |||
48 | static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) | 126 | static int ql_get_mb_sts(struct ql_adapter *qdev, struct mbox_params *mbcp) |
49 | { | 127 | { |
50 | int i, status; | 128 | int i, status; |
@@ -529,6 +607,22 @@ end: | |||
529 | return status; | 607 | return status; |
530 | } | 608 | } |
531 | 609 | ||
610 | int ql_mb_sys_err(struct ql_adapter *qdev) | ||
611 | { | ||
612 | struct mbox_params mbc; | ||
613 | struct mbox_params *mbcp = &mbc; | ||
614 | int status; | ||
615 | |||
616 | memset(mbcp, 0, sizeof(struct mbox_params)); | ||
617 | |||
618 | mbcp->in_count = 1; | ||
619 | mbcp->out_count = 0; | ||
620 | |||
621 | mbcp->mbox_in[0] = MB_CMD_MAKE_SYS_ERR; | ||
622 | |||
623 | status = ql_mailbox_command(qdev, mbcp); | ||
624 | return status; | ||
625 | } | ||
532 | 626 | ||
533 | /* Get MPI firmware version. This will be used for | 627 | /* Get MPI firmware version. This will be used for |
534 | * driver banner and for ethtool info. | 628 | * driver banner and for ethtool info. |
@@ -669,6 +763,63 @@ int ql_mb_set_port_cfg(struct ql_adapter *qdev) | |||
669 | return status; | 763 | return status; |
670 | } | 764 | } |
671 | 765 | ||
766 | int ql_mb_dump_ram(struct ql_adapter *qdev, u64 req_dma, u32 addr, | ||
767 | u32 size) | ||
768 | { | ||
769 | int status = 0; | ||
770 | struct mbox_params mbc; | ||
771 | struct mbox_params *mbcp = &mbc; | ||
772 | |||
773 | memset(mbcp, 0, sizeof(struct mbox_params)); | ||
774 | |||
775 | mbcp->in_count = 9; | ||
776 | mbcp->out_count = 1; | ||
777 | |||
778 | mbcp->mbox_in[0] = MB_CMD_DUMP_RISC_RAM; | ||
779 | mbcp->mbox_in[1] = LSW(addr); | ||
780 | mbcp->mbox_in[2] = MSW(req_dma); | ||
781 | mbcp->mbox_in[3] = LSW(req_dma); | ||
782 | mbcp->mbox_in[4] = MSW(size); | ||
783 | mbcp->mbox_in[5] = LSW(size); | ||
784 | mbcp->mbox_in[6] = MSW(MSD(req_dma)); | ||
785 | mbcp->mbox_in[7] = LSW(MSD(req_dma)); | ||
786 | mbcp->mbox_in[8] = MSW(addr); | ||
787 | |||
788 | |||
789 | status = ql_mailbox_command(qdev, mbcp); | ||
790 | if (status) | ||
791 | return status; | ||
792 | |||
793 | if (mbcp->mbox_out[0] != MB_CMD_STS_GOOD) { | ||
794 | QPRINTK(qdev, DRV, ERR, | ||
795 | "Failed to dump risc RAM.\n"); | ||
796 | status = -EIO; | ||
797 | } | ||
798 | return status; | ||
799 | } | ||
800 | |||
801 | /* Issue a mailbox command to dump RISC RAM. */ | ||
802 | int ql_dump_risc_ram_area(struct ql_adapter *qdev, void *buf, | ||
803 | u32 ram_addr, int word_count) | ||
804 | { | ||
805 | int status; | ||
806 | char *my_buf; | ||
807 | dma_addr_t buf_dma; | ||
808 | |||
809 | my_buf = pci_alloc_consistent(qdev->pdev, word_count * sizeof(u32), | ||
810 | &buf_dma); | ||
811 | if (!my_buf) | ||
812 | return -EIO; | ||
813 | |||
814 | status = ql_mb_dump_ram(qdev, buf_dma, ram_addr, word_count); | ||
815 | if (!status) | ||
816 | memcpy(buf, my_buf, word_count * sizeof(u32)); | ||
817 | |||
818 | pci_free_consistent(qdev->pdev, word_count * sizeof(u32), my_buf, | ||
819 | buf_dma); | ||
820 | return status; | ||
821 | } | ||
822 | |||
672 | /* Get link settings and maximum frame size settings | 823 | /* Get link settings and maximum frame size settings |
673 | * for the current port. | 824 | * for the current port. |
674 | * Most likely will block. | 825 | * Most likely will block. |
@@ -1143,5 +1294,19 @@ void ql_mpi_reset_work(struct work_struct *work) | |||
1143 | cancel_delayed_work_sync(&qdev->mpi_work); | 1294 | cancel_delayed_work_sync(&qdev->mpi_work); |
1144 | cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); | 1295 | cancel_delayed_work_sync(&qdev->mpi_port_cfg_work); |
1145 | cancel_delayed_work_sync(&qdev->mpi_idc_work); | 1296 | cancel_delayed_work_sync(&qdev->mpi_idc_work); |
1297 | /* If we're not the dominant NIC function, | ||
1298 | * then there is nothing to do. | ||
1299 | */ | ||
1300 | if (!ql_own_firmware(qdev)) { | ||
1301 | QPRINTK(qdev, DRV, ERR, "Don't own firmware!\n"); | ||
1302 | return; | ||
1303 | } | ||
1304 | |||
1305 | if (!ql_core_dump(qdev, qdev->mpi_coredump)) { | ||
1306 | QPRINTK(qdev, DRV, ERR, "Core is dumped!\n"); | ||
1307 | qdev->core_is_dumped = 1; | ||
1308 | queue_delayed_work(qdev->workqueue, | ||
1309 | &qdev->mpi_core_to_log, 5 * HZ); | ||
1310 | } | ||
1146 | ql_soft_reset_mpi_risc(qdev); | 1311 | ql_soft_reset_mpi_risc(qdev); |
1147 | } | 1312 | } |