Newer
Older
* This program is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* as published by the Free Software Foundation; either version 2
* of the License, or (at your option) any later version.
* This program is distributed in the hope that it will be useful, but
* WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place - Suite 330, Boston,
* MA 02111-1307, USA.
* The full GNU General Public License is included in this distribution
*/
#include <linux/netdevice.h>
#include <linux/delay.h>
#include <linux/slab.h>
#include "netxen_nic.h"
#include "netxen_nic_hw.h"
struct crb_addr_pair {
Linsys Contractor Mithlesh Thukral
committed
u32 addr;
u32 data;
};
#define NETXEN_MAX_CRB_XFORM 60
static unsigned int crb_addr_xform[NETXEN_MAX_CRB_XFORM];
Linsys Contractor Mithlesh Thukral
committed
#define NETXEN_ADDR_ERROR (0xffffffff)
#define crb_addr_transform(name) \
crb_addr_xform[NETXEN_HW_PX_MAP_CRB_##name] = \
NETXEN_HW_CRB_HUB_AGT_ADR_##name << 20
Amit S. Kale
committed
#define NETXEN_NIC_XDMA_RESET 0x8000ff
netxen_post_rx_buffers_nodb(struct netxen_adapter *adapter,
struct nx_host_rds_ring *rds_ring);
static int netxen_p3_has_mn(struct netxen_adapter *adapter);
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
static void crb_addr_transform_setup(void)
{
crb_addr_transform(XDMA);
crb_addr_transform(TIMR);
crb_addr_transform(SRE);
crb_addr_transform(SQN3);
crb_addr_transform(SQN2);
crb_addr_transform(SQN1);
crb_addr_transform(SQN0);
crb_addr_transform(SQS3);
crb_addr_transform(SQS2);
crb_addr_transform(SQS1);
crb_addr_transform(SQS0);
crb_addr_transform(RPMX7);
crb_addr_transform(RPMX6);
crb_addr_transform(RPMX5);
crb_addr_transform(RPMX4);
crb_addr_transform(RPMX3);
crb_addr_transform(RPMX2);
crb_addr_transform(RPMX1);
crb_addr_transform(RPMX0);
crb_addr_transform(ROMUSB);
crb_addr_transform(SN);
crb_addr_transform(QMN);
crb_addr_transform(QMS);
crb_addr_transform(PGNI);
crb_addr_transform(PGND);
crb_addr_transform(PGN3);
crb_addr_transform(PGN2);
crb_addr_transform(PGN1);
crb_addr_transform(PGN0);
crb_addr_transform(PGSI);
crb_addr_transform(PGSD);
crb_addr_transform(PGS3);
crb_addr_transform(PGS2);
crb_addr_transform(PGS1);
crb_addr_transform(PGS0);
crb_addr_transform(PS);
crb_addr_transform(PH);
crb_addr_transform(NIU);
crb_addr_transform(I2Q);
crb_addr_transform(EG);
crb_addr_transform(MN);
crb_addr_transform(MS);
crb_addr_transform(CAS2);
crb_addr_transform(CAS1);
crb_addr_transform(CAS0);
crb_addr_transform(CAM);
crb_addr_transform(C2C1);
crb_addr_transform(C2C0);
crb_addr_transform(OCM0);
crb_addr_transform(I2C0);
void netxen_release_rx_buffers(struct netxen_adapter *adapter)
struct netxen_recv_context *recv_ctx;
struct netxen_rx_buffer *rx_buf;
int i, ring;
recv_ctx = &adapter->recv_ctx;
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
for (i = 0; i < rds_ring->num_desc; ++i) {
rx_buf = &(rds_ring->rx_buf_arr[i]);
if (rx_buf->state == NETXEN_BUFFER_FREE)
continue;
pci_unmap_single(adapter->pdev,
rx_buf->dma,
rds_ring->dma_size,
PCI_DMA_FROMDEVICE);
if (rx_buf->skb != NULL)
dev_kfree_skb_any(rx_buf->skb);
}
}
}
void netxen_release_tx_buffers(struct netxen_adapter *adapter)
{
struct netxen_cmd_buffer *cmd_buf;
struct netxen_skb_frag *buffrag;
int i, j;
struct nx_host_tx_ring *tx_ring = adapter->tx_ring;
cmd_buf = tx_ring->cmd_buf_arr;
for (i = 0; i < tx_ring->num_desc; i++) {
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
buffrag = cmd_buf->frag_array;
if (buffrag->dma) {
pci_unmap_single(adapter->pdev, buffrag->dma,
buffrag->length, PCI_DMA_TODEVICE);
buffrag->dma = 0ULL;
}
for (j = 0; j < cmd_buf->frag_count; j++) {
buffrag++;
if (buffrag->dma) {
pci_unmap_page(adapter->pdev, buffrag->dma,
buffrag->length,
PCI_DMA_TODEVICE);
buffrag->dma = 0ULL;
}
}
if (cmd_buf->skb) {
dev_kfree_skb_any(cmd_buf->skb);
cmd_buf->skb = NULL;
}
cmd_buf++;
}
}
void netxen_free_sw_resources(struct netxen_adapter *adapter)
{
struct netxen_recv_context *recv_ctx;
int ring;
recv_ctx = &adapter->recv_ctx;
if (recv_ctx->rds_rings == NULL)
goto skip_rds;
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
vfree(rds_ring->rx_buf_arr);
rds_ring->rx_buf_arr = NULL;
kfree(recv_ctx->rds_rings);
skip_rds:
if (adapter->tx_ring == NULL)
return;
tx_ring = adapter->tx_ring;
kfree(tx_ring);
adapter->tx_ring = NULL;
}
int netxen_alloc_sw_resources(struct netxen_adapter *adapter)
{
struct netxen_recv_context *recv_ctx;
struct nx_host_sds_ring *sds_ring;
struct nx_host_tx_ring *tx_ring;
struct netxen_rx_buffer *rx_buf;
struct netxen_cmd_buffer *cmd_buf_arr;
struct net_device *netdev = adapter->netdev;
size = sizeof(struct nx_host_tx_ring);
tx_ring = kzalloc(size, GFP_KERNEL);
if (tx_ring == NULL) {
dev_err(&pdev->dev, "%s: failed to allocate tx ring struct\n",
netdev->name);
return -ENOMEM;
}
adapter->tx_ring = tx_ring;
tx_ring->txq = netdev_get_tx_queue(netdev, 0);
cmd_buf_arr = vzalloc(TX_BUFF_RINGSIZE(tx_ring));
if (cmd_buf_arr == NULL) {
dev_err(&pdev->dev, "%s: failed to allocate cmd buffer ring\n",
recv_ctx = &adapter->recv_ctx;
size = adapter->max_rds_rings * sizeof (struct nx_host_rds_ring);
rds_ring = kzalloc(size, GFP_KERNEL);
if (rds_ring == NULL) {
dev_err(&pdev->dev, "%s: failed to allocate rds ring struct\n",
netdev->name);
}
recv_ctx->rds_rings = rds_ring;
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
rds_ring = &recv_ctx->rds_rings[ring];
switch (ring) {
case RCV_RING_NORMAL:
rds_ring->num_desc = adapter->num_rxd;
if (adapter->ahw.cut_through) {
rds_ring->dma_size =
NX_CT_DEFAULT_RX_BUF_LEN;
NX_CT_DEFAULT_RX_BUF_LEN;
} else {
if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
rds_ring->dma_size =
NX_P3_RX_BUF_MAX_LEN;
else
rds_ring->dma_size =
NX_P2_RX_BUF_MAX_LEN;
rds_ring->dma_size + NET_IP_ALIGN;
case RCV_RING_JUMBO:
rds_ring->num_desc = adapter->num_jumbo_rxd;
if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
rds_ring->dma_size =
NX_P3_RX_JUMBO_BUF_MAX_LEN;
else
rds_ring->dma_size =
NX_P2_RX_JUMBO_BUF_MAX_LEN;
if (adapter->capabilities & NX_CAP0_HW_LRO)
rds_ring->dma_size += NX_LRO_BUFFER_EXTRA;
rds_ring->skb_size =
rds_ring->dma_size + NET_IP_ALIGN;
break;
rds_ring->num_desc = adapter->num_lro_rxd;
rds_ring->dma_size = NX_RX_LRO_BUFFER_LENGTH;
rds_ring->skb_size = rds_ring->dma_size + NET_IP_ALIGN;
rds_ring->rx_buf_arr = vzalloc(RCV_BUFF_RINGSIZE(rds_ring));
if (rds_ring->rx_buf_arr == NULL) {
printk(KERN_ERR "%s: Failed to allocate "
"rx buffer ring %d\n",
netdev->name, ring);
/* free whatever was already allocated */
goto err_out;
}
INIT_LIST_HEAD(&rds_ring->free_list);
/*
* Now go through all of them, set reference handles
* and put them in the queues.
*/
rx_buf = rds_ring->rx_buf_arr;
for (i = 0; i < rds_ring->num_desc; i++) {
list_add_tail(&rx_buf->list,
&rds_ring->free_list);
rx_buf->ref_handle = i;
rx_buf->state = NETXEN_BUFFER_FREE;
rx_buf++;
spin_lock_init(&rds_ring->lock);
}
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
sds_ring->irq = adapter->msix_entries[ring].vector;
sds_ring->adapter = adapter;
sds_ring->num_desc = adapter->num_rxd;
for (i = 0; i < NUM_RCV_DESC_RINGS; i++)
INIT_LIST_HEAD(&sds_ring->free_list[i]);
return 0;
err_out:
netxen_free_sw_resources(adapter);
return -ENOMEM;
}
/*
* netxen_decode_crb_addr(0 - utility to translate from internal Phantom CRB
* address to external PCI CRB address.
*/
Linsys Contractor Mithlesh Thukral
committed
u32 base_addr, offset, pci_base;
crb_addr_transform_setup();
pci_base = NETXEN_ADDR_ERROR;
base_addr = addr & 0xfff00000;
offset = addr & 0x000fffff;
for (i = 0; i < NETXEN_MAX_CRB_XFORM; i++) {
if (crb_addr_xform[i] == base_addr) {
pci_base = i << 20;
break;
}
}
if (pci_base == NETXEN_ADDR_ERROR)
return pci_base;
else
#define NETXEN_MAX_ROM_WAIT_USEC 100
static int netxen_wait_rom_done(struct netxen_adapter *adapter)
{
long timeout = 0;
long done = 0;
done = NXRD32(adapter, NETXEN_ROMUSB_GLB_STATUS);
if (++timeout >= NETXEN_MAX_ROM_WAIT_USEC) {
dev_err(&adapter->pdev->dev,
"Timeout reached waiting for rom done");
static int do_rom_fast_read(struct netxen_adapter *adapter,
int addr, int *valp)
NXWR32(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
NXWR32(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
NXWR32(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
NXWR32(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb);
if (netxen_wait_rom_done(adapter)) {
printk("Error waiting for rom done\n");
return -EIO;
}
/* reset abyte_cnt and dummy_byte_cnt */
NXWR32(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
NXWR32(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
*valp = NXRD32(adapter, NETXEN_ROMUSB_ROM_RDATA);
static int do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
u8 *bytes, size_t size)
{
int addridx;
int ret = 0;
for (addridx = addr; addridx < (addr + size); addridx += 4) {
if (ret != 0)
break;
bytes += 4;
}
return ret;
}
int
netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
u8 *bytes, size_t size)
{
int ret;
ret = netxen_rom_lock(adapter);
if (ret < 0)
return ret;
ret = do_rom_fast_read_words(adapter, addr, bytes, size);
netxen_rom_unlock(adapter);
return ret;
}
int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
{
int ret;
if (netxen_rom_lock(adapter) != 0)
return -EIO;
ret = do_rom_fast_read(adapter, addr, valp);
Amit S. Kale
committed
netxen_rom_unlock(adapter);
return ret;
}
#define NETXEN_BOARDTYPE 0x4008
#define NETXEN_BOARDNUM 0x400c
#define NETXEN_CHIPNUM 0x4010
int netxen_pinit_from_rom(struct netxen_adapter *adapter)
Linsys Contractor Mithlesh Thukral
committed
u32 off;
netxen_rom_lock(adapter);
NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xffffffff);
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
if (netxen_rom_fast_read(adapter, 0, &n) != 0 ||
netxen_rom_fast_read(adapter, 4, &n) != 0) {
printk(KERN_ERR "%s: ERROR Reading crb_init area: "
"n: %08x\n", netxen_nic_driver_name, n);
offset = n & 0xffffU;
n = (n >> 16) & 0xffffU;
} else {
if (netxen_rom_fast_read(adapter, 0, &n) != 0 ||
!(n & 0x80000000)) {
printk(KERN_ERR "%s: ERROR Reading crb_init area: "
"n: %08x\n", netxen_nic_driver_name, n);
return -EIO;
offset = 1;
n &= ~0x80000000;
}
printk(KERN_ERR "%s:n=0x%x Error! NetXen card flash not"
" initialized.\n", __func__, n);
return -EIO;
}
buf = kcalloc(n, sizeof(struct crb_addr_pair), GFP_KERNEL);
if (buf == NULL) {
printk("%s: netxen_pinit_from_rom: Unable to calloc memory.\n",
netxen_nic_driver_name);
return -ENOMEM;
}
for (i = 0; i < n; i++) {
if (netxen_rom_fast_read(adapter, 8*i + 4*offset, &val) != 0 ||
netxen_rom_fast_read(adapter, 8*i + 4*offset + 4, &addr) != 0) {
kfree(buf);
buf[i].addr = addr;
buf[i].data = val;
}
for (i = 0; i < n; i++) {
off = netxen_decode_crb_addr(buf[i].addr);
if (off == NETXEN_ADDR_ERROR) {
printk(KERN_ERR"CRB init value out of range %x\n",
continue;
}
off += NETXEN_PCI_CRBSPACE;
/* skipping cold reboot MAGIC */
if (off == NETXEN_CAM_RAM(0x1fc))
continue;
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
if (off == (NETXEN_CRB_I2C0 + 0x1c))
continue;
/* do not reset PCI */
if (off == (ROMUSB_GLB + 0xbc))
if (off == (ROMUSB_GLB + 0xa8))
continue;
if (off == (ROMUSB_GLB + 0xc8)) /* core clock */
continue;
if (off == (ROMUSB_GLB + 0x24)) /* MN clock */
continue;
if (off == (ROMUSB_GLB + 0x1c)) /* MS clock */
continue;
if ((off & 0x0ff00000) == NETXEN_CRB_DDR_NET)
continue;
if (off == (NETXEN_CRB_PEG_NET_1 + 0x18) &&
!NX_IS_REVISION_P3P(adapter->ahw.revision_id))
buf[i].data = 0x1020;
/* skip the function enable register */
if (off == NETXEN_PCIE_REG(PCIE_SETUP_FUNCTION))
if (off == NETXEN_PCIE_REG(PCIE_SETUP_FUNCTION2))
continue;
if ((off & 0x0ff00000) == NETXEN_CRB_SMB)
continue;
}
/* After writing this register, HW needs time for CRB */
/* to quiet down (else crb_window returns 0xffffffff) */
if (off == NETXEN_ROMUSB_GLB_SW_RESET) {
if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
Amit S. Kale
committed
buf[i].data = NETXEN_NIC_XDMA_RESET;
/* disable_peg_cache_all */
/* unreset_net_cache */
if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
val = NXRD32(adapter, NETXEN_ROMUSB_GLB_SW_RESET);
NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, (val & 0xffffff0f));
/* p2dn replyCount */
NXWR32(adapter, NETXEN_CRB_PEG_NET_D + 0xec, 0x1e);
/* disable_peg_cache 0 */
NXWR32(adapter, NETXEN_CRB_PEG_NET_D + 0x4c, 8);
/* disable_peg_cache 1 */
NXWR32(adapter, NETXEN_CRB_PEG_NET_I + 0x4c, 8);
/* peg_clr_all */
/* peg_clr 0 */
NXWR32(adapter, NETXEN_CRB_PEG_NET_0 + 0x8, 0);
NXWR32(adapter, NETXEN_CRB_PEG_NET_0 + 0xc, 0);
NXWR32(adapter, NETXEN_CRB_PEG_NET_1 + 0x8, 0);
NXWR32(adapter, NETXEN_CRB_PEG_NET_1 + 0xc, 0);
NXWR32(adapter, NETXEN_CRB_PEG_NET_2 + 0x8, 0);
NXWR32(adapter, NETXEN_CRB_PEG_NET_2 + 0xc, 0);
NXWR32(adapter, NETXEN_CRB_PEG_NET_3 + 0x8, 0);
NXWR32(adapter, NETXEN_CRB_PEG_NET_3 + 0xc, 0);
static struct uni_table_desc *nx_get_table_desc(const u8 *unirom, int section)
{
uint32_t i;
struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0];
__le32 entries = cpu_to_le32(directory->num_entries);
for (i = 0; i < entries; i++) {
__le32 offs = cpu_to_le32(directory->findex) +
(i * cpu_to_le32(directory->entry_size));
__le32 tab_type = cpu_to_le32(*((u32 *)&unirom[offs] + 8));
if (tab_type == section)
return (struct uni_table_desc *) &unirom[offs];
}
return NULL;
}
#define QLCNIC_FILEHEADER_SIZE (14 * 4)
netxen_nic_validate_header(struct netxen_adapter *adapter)
{
const u8 *unirom = adapter->fw->data;
struct uni_table_desc *directory = (struct uni_table_desc *) &unirom[0];
u32 fw_file_size = adapter->fw->size;
u32 tab_size;
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
__le32 entry_size;
if (fw_file_size < QLCNIC_FILEHEADER_SIZE)
return -EINVAL;
entries = cpu_to_le32(directory->num_entries);
entry_size = cpu_to_le32(directory->entry_size);
tab_size = cpu_to_le32(directory->findex) + (entries * entry_size);
if (fw_file_size < tab_size)
return -EINVAL;
return 0;
}
static int
netxen_nic_validate_bootld(struct netxen_adapter *adapter)
{
struct uni_table_desc *tab_desc;
struct uni_data_desc *descr;
const u8 *unirom = adapter->fw->data;
__le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
NX_UNI_BOOTLD_IDX_OFF));
u32 offs;
u32 tab_size;
u32 data_size;
tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_BOOTLD);
if (!tab_desc)
return -EINVAL;
tab_size = cpu_to_le32(tab_desc->findex) +
(cpu_to_le32(tab_desc->entry_size) * (idx + 1));
if (adapter->fw->size < tab_size)
return -EINVAL;
offs = cpu_to_le32(tab_desc->findex) +
(cpu_to_le32(tab_desc->entry_size) * (idx));
descr = (struct uni_data_desc *)&unirom[offs];
data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size);
if (adapter->fw->size < data_size)
return -EINVAL;
return 0;
}
static int
netxen_nic_validate_fw(struct netxen_adapter *adapter)
{
struct uni_table_desc *tab_desc;
struct uni_data_desc *descr;
const u8 *unirom = adapter->fw->data;
__le32 idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
NX_UNI_FIRMWARE_IDX_OFF));
u32 offs;
u32 tab_size;
u32 data_size;
tab_desc = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_FW);
if (!tab_desc)
return -EINVAL;
tab_size = cpu_to_le32(tab_desc->findex) +
(cpu_to_le32(tab_desc->entry_size) * (idx + 1));
if (adapter->fw->size < tab_size)
return -EINVAL;
offs = cpu_to_le32(tab_desc->findex) +
(cpu_to_le32(tab_desc->entry_size) * (idx));
descr = (struct uni_data_desc *)&unirom[offs];
data_size = cpu_to_le32(descr->findex) + cpu_to_le32(descr->size);
if (adapter->fw->size < data_size)
return -EINVAL;
return 0;
}
static int
netxen_nic_validate_product_offs(struct netxen_adapter *adapter)
{
struct uni_table_desc *ptab_descr;
const u8 *unirom = adapter->fw->data;
int mn_present = (NX_IS_REVISION_P2(adapter->ahw.revision_id)) ?
1 : netxen_p3_has_mn(adapter);
__le32 entries;
__le32 entry_size;
u32 tab_size;
u32 i;
ptab_descr = nx_get_table_desc(unirom, NX_UNI_DIR_SECT_PRODUCT_TBL);
if (ptab_descr == NULL)
entries = cpu_to_le32(ptab_descr->num_entries);
entry_size = cpu_to_le32(ptab_descr->entry_size);
tab_size = cpu_to_le32(ptab_descr->findex) + (entries * entry_size);
if (adapter->fw->size < tab_size)
return -EINVAL;
for (i = 0; i < entries; i++) {
__le32 flags, file_chiprev, offs;
u8 chiprev = adapter->ahw.revision_id;
uint32_t flagbit;
offs = cpu_to_le32(ptab_descr->findex) +
(i * cpu_to_le32(ptab_descr->entry_size));
flags = cpu_to_le32(*((int *)&unirom[offs] + NX_UNI_FLAGS_OFF));
file_chiprev = cpu_to_le32(*((int *)&unirom[offs] +
NX_UNI_CHIP_REV_OFF));
flagbit = mn_present ? 1 : 2;
if ((chiprev == file_chiprev) &&
((1ULL << flagbit) & flags)) {
adapter->file_prd_off = offs;
return 0;
}
}
if (mn_present && NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
mn_present = 0;
goto nomn;
}
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
static int
netxen_nic_validate_unified_romimage(struct netxen_adapter *adapter)
{
if (netxen_nic_validate_header(adapter)) {
dev_err(&adapter->pdev->dev,
"unified image: header validation failed\n");
return -EINVAL;
}
if (netxen_nic_validate_product_offs(adapter)) {
dev_err(&adapter->pdev->dev,
"unified image: product validation failed\n");
return -EINVAL;
}
if (netxen_nic_validate_bootld(adapter)) {
dev_err(&adapter->pdev->dev,
"unified image: bootld validation failed\n");
return -EINVAL;
}
if (netxen_nic_validate_fw(adapter)) {
dev_err(&adapter->pdev->dev,
"unified image: firmware validation failed\n");
return -EINVAL;
}
return 0;
}
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
static struct uni_data_desc *nx_get_data_desc(struct netxen_adapter *adapter,
u32 section, u32 idx_offset)
{
const u8 *unirom = adapter->fw->data;
int idx = cpu_to_le32(*((int *)&unirom[adapter->file_prd_off] +
idx_offset));
struct uni_table_desc *tab_desc;
__le32 offs;
tab_desc = nx_get_table_desc(unirom, section);
if (tab_desc == NULL)
return NULL;
offs = cpu_to_le32(tab_desc->findex) +
(cpu_to_le32(tab_desc->entry_size) * idx);
return (struct uni_data_desc *)&unirom[offs];
}
static u8 *
nx_get_bootld_offs(struct netxen_adapter *adapter)
{
u32 offs = NETXEN_BOOTLD_START;
if (adapter->fw_type == NX_UNIFIED_ROMIMAGE)
offs = cpu_to_le32((nx_get_data_desc(adapter,
NX_UNI_DIR_SECT_BOOTLD,
NX_UNI_BOOTLD_IDX_OFF))->findex);
return (u8 *)&adapter->fw->data[offs];
}
static u8 *
nx_get_fw_offs(struct netxen_adapter *adapter)
{
u32 offs = NETXEN_IMAGE_START;
if (adapter->fw_type == NX_UNIFIED_ROMIMAGE)
offs = cpu_to_le32((nx_get_data_desc(adapter,
NX_UNI_DIR_SECT_FW,
NX_UNI_FIRMWARE_IDX_OFF))->findex);
return (u8 *)&adapter->fw->data[offs];
}
static __le32
nx_get_fw_size(struct netxen_adapter *adapter)
{
if (adapter->fw_type == NX_UNIFIED_ROMIMAGE)
return cpu_to_le32((nx_get_data_desc(adapter,
NX_UNI_DIR_SECT_FW,
NX_UNI_FIRMWARE_IDX_OFF))->size);
else
return cpu_to_le32(
*(u32 *)&adapter->fw->data[NX_FW_SIZE_OFFSET]);
}
static __le32
nx_get_fw_version(struct netxen_adapter *adapter)
{
struct uni_data_desc *fw_data_desc;
const struct firmware *fw = adapter->fw;
__le32 major, minor, sub;
const u8 *ver_str;
int i, ret = 0;
if (adapter->fw_type == NX_UNIFIED_ROMIMAGE) {
fw_data_desc = nx_get_data_desc(adapter,
NX_UNI_DIR_SECT_FW, NX_UNI_FIRMWARE_IDX_OFF);
ver_str = fw->data + cpu_to_le32(fw_data_desc->findex) +
cpu_to_le32(fw_data_desc->size) - 17;
for (i = 0; i < 12; i++) {
if (!strncmp(&ver_str[i], "REV=", 4)) {
ret = sscanf(&ver_str[i+4], "%u.%u.%u ",
&major, &minor, &sub);
break;
}
}
if (ret != 3)
return 0;
return major + (minor << 8) + (sub << 16);
} else
return cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]);
}
static __le32
nx_get_bios_version(struct netxen_adapter *adapter)
{
const struct firmware *fw = adapter->fw;
__le32 bios_ver, prd_off = adapter->file_prd_off;
if (adapter->fw_type == NX_UNIFIED_ROMIMAGE) {
bios_ver = cpu_to_le32(*((u32 *) (&fw->data[prd_off])
+ NX_UNI_BIOS_VERSION_OFF));
return (bios_ver << 16) + ((bios_ver >> 8) & 0xff00) +
(bios_ver >> 24);
} else
return cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]);
}
int
netxen_need_fw_reset(struct netxen_adapter *adapter)
{
u32 count, old_count;
u32 val, version, major, minor, build;
int i, timeout;
u8 fw_type;
/* NX2031 firmware doesn't support heartbit */
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
return 1;
if (adapter->need_fw_reset)
return 1;
/* last attempt had failed */
if (NXRD32(adapter, CRB_CMDPEG_STATE) == PHAN_INITIALIZE_FAILED)
return 1;
old_count = NXRD32(adapter, NETXEN_PEG_ALIVE_COUNTER);
for (i = 0; i < 10; i++) {
timeout = msleep_interruptible(200);
if (timeout) {
NXWR32(adapter, CRB_CMDPEG_STATE,
PHAN_INITIALIZE_FAILED);
return -EINTR;
}
count = NXRD32(adapter, NETXEN_PEG_ALIVE_COUNTER);
if (count != old_count)
break;
}
/* firmware is dead */
if (count == old_count)
return 1;
/* check if we have got newer or different file firmware */
if (adapter->fw) {
val = nx_get_fw_version(adapter);
version = NETXEN_DECODE_VERSION(val);
major = NXRD32(adapter, NETXEN_FW_VERSION_MAJOR);
minor = NXRD32(adapter, NETXEN_FW_VERSION_MINOR);
build = NXRD32(adapter, NETXEN_FW_VERSION_SUB);
if (version > NETXEN_VERSION_CODE(major, minor, build))
return 1;
if (version == NETXEN_VERSION_CODE(major, minor, build) &&
adapter->fw_type != NX_UNIFIED_ROMIMAGE) {
val = NXRD32(adapter, NETXEN_MIU_MN_CONTROL);
fw_type = (val & 0x4) ?
NX_P3_CT_ROMIMAGE : NX_P3_MN_ROMIMAGE;
if (adapter->fw_type != fw_type)
return 1;
}
}
return 0;
}
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
#define NETXEN_MIN_P3_FW_SUPP NETXEN_VERSION_CODE(4, 0, 505)
int
netxen_check_flash_fw_compatibility(struct netxen_adapter *adapter)
{
u32 flash_fw_ver, min_fw_ver;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
return 0;
if (netxen_rom_fast_read(adapter,
NX_FW_VERSION_OFFSET, (int *)&flash_fw_ver)) {
dev_err(&adapter->pdev->dev, "Unable to read flash fw"
"version\n");
return -EIO;
}
flash_fw_ver = NETXEN_DECODE_VERSION(flash_fw_ver);
min_fw_ver = NETXEN_MIN_P3_FW_SUPP;
if (flash_fw_ver >= min_fw_ver)
return 0;
dev_info(&adapter->pdev->dev, "Flash fw[%d.%d.%d] is < min fw supported"
"[4.0.505]. Please update firmware on flash\n",
_major(flash_fw_ver), _minor(flash_fw_ver),
_build(flash_fw_ver));
return -EINVAL;
}
NX_P2_MN_ROMIMAGE_NAME,
NX_P3_CT_ROMIMAGE_NAME,
NX_P3_MN_ROMIMAGE_NAME,
NX_UNIFIED_ROMIMAGE_NAME,