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
* in the file called LICENSE.
* Contact Information:
* info@netxen.com
* NetXen Inc,
* 18922 Forge Drive
* Cupertino, CA 95014-0701
*
*/
#include <linux/netdevice.h>
#include <linux/delay.h>
#include "netxen_nic.h"
#include "netxen_nic_hw.h"
#include "netxen_nic_phan_reg.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);
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
102
103
104
105
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++) {
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
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;
}
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;
cmd_buf_arr = vmalloc(TX_BUFF_RINGSIZE(tx_ring));
if (cmd_buf_arr == NULL) {
dev_err(&pdev->dev, "%s: failed to allocate cmd buffer ring\n",
netdev->name);
return -ENOMEM;
}
memset(cmd_buf_arr, 0, TX_BUFF_RINGSIZE(tx_ring));
tx_ring->cmd_buf_arr = cmd_buf_arr;
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);
return -ENOMEM;
}
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 {
rds_ring->dma_size = RX_DMA_MAP_LEN;
rds_ring->skb_size =
MAX_RX_BUFFER_LENGTH;
}
break;
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;
rds_ring->skb_size =
rds_ring->dma_size + NET_IP_ALIGN;
break;
rds_ring->num_desc = adapter->num_lro_rxd;
rds_ring->dma_size = RX_LRO_DMA_MAP_LEN;
rds_ring->skb_size = MAX_RX_LRO_BUFFER_LENGTH;
break;
}
rds_ring->rx_buf_arr = (struct netxen_rx_buffer *)
vmalloc(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;
}
memset(rds_ring->rx_buf_arr, 0, RCV_BUFF_RINGSIZE(rds_ring));
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;
}
void netxen_initialize_adapter_ops(struct netxen_adapter *adapter)
{
adapter->macaddr_set = netxen_p2_nic_set_mac_addr;
adapter->set_multi = netxen_p2_nic_set_multi;
switch (adapter->ahw.port_type) {
adapter->enable_phy_interrupts =
adapter->disable_phy_interrupts =
netxen_niu_gbe_disable_phy_interrupts;
adapter->set_mtu = netxen_nic_set_mtu_gb;
adapter->set_promisc = netxen_niu_set_promiscuous_mode;
adapter->phy_read = netxen_niu_gbe_phy_read;
adapter->phy_write = netxen_niu_gbe_phy_write;
adapter->init_port = netxen_niu_gbe_init_port;
adapter->stop_port = netxen_niu_disable_gbe_port;
adapter->enable_phy_interrupts =
netxen_niu_xgbe_enable_phy_interrupts;
adapter->disable_phy_interrupts =
netxen_niu_xgbe_disable_phy_interrupts;
adapter->set_mtu = netxen_nic_set_mtu_xgb;
adapter->init_port = netxen_niu_xg_init_port;
adapter->set_promisc = netxen_niu_xg_set_promiscuous_mode;
adapter->stop_port = netxen_niu_disable_xg_port;
break;
default:
break;
}
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
adapter->set_mtu = nx_fw_cmd_set_mtu;
adapter->set_promisc = netxen_p3_nic_set_promisc;
adapter->macaddr_set = netxen_p3_nic_set_mac_addr;
adapter->set_multi = netxen_p3_nic_set_multi;
}
/*
* 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
return (pci_base + offset);
}
static long rom_max_timeout = 100;
static long rom_lock_timeout = 10000;
static int rom_lock(struct netxen_adapter *adapter)
{
int iter;
u32 done = 0;
int timeout = 0;
while (!done) {
/* acquire semaphore2 from PCI HW block */
done = NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM2_LOCK));
if (done == 1)
break;
if (timeout >= rom_lock_timeout)
return -EIO;
timeout++;
/*
* Yield CPU
*/
if (!in_atomic())
schedule();
else {
for (iter = 0; iter < 20; iter++)
cpu_relax(); /*This a nop instr on i386 */
}
}
NXWR32(adapter, NETXEN_ROM_LOCK_ID, ROM_LOCK_DRIVER);
static int netxen_wait_rom_done(struct netxen_adapter *adapter)
{
long timeout = 0;
long done = 0;
done = NXRD32(adapter, NETXEN_ROMUSB_GLB_STATUS);
done &= 2;
timeout++;
if (timeout >= rom_max_timeout) {
printk("Timeout reached waiting for rom done");
return -EIO;
}
}
return 0;
}
static void netxen_rom_unlock(struct netxen_adapter *adapter)
Amit S. Kale
committed
{
/* release semaphore2 */
NXRD32(adapter, NETXEN_PCIE_REG(PCIE_SEM2_UNLOCK));
Amit S. Kale
committed
}
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 = 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 (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, int verbose)
{
Linsys Contractor Mithlesh Thukral
committed
u32 off;
NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0xffffffff);
if (verbose) {
if (netxen_rom_fast_read(adapter, NETXEN_BOARDTYPE, &val) == 0)
printk("P2 ROM board type: 0x%08x\n", val);
else
printk("Could not read board type\n");
if (netxen_rom_fast_read(adapter, NETXEN_BOARDNUM, &val) == 0)
printk("P2 ROM board num: 0x%08x\n", val);
else
printk("Could not read board number\n");
if (netxen_rom_fast_read(adapter, NETXEN_CHIPNUM, &val) == 0)
printk("P2 ROM chip num: 0x%08x\n", val);
else
printk("Could not read chip number\n");
}
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;
}
if (n < 1024) {
if (verbose)
printk(KERN_DEBUG "%s: %d CRB init values found"
" in ROM.\n", netxen_nic_driver_name, n);
} else {
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;
if (verbose)
printk(KERN_DEBUG "%s: PCI: 0x%08x == 0x%08x\n",
netxen_nic_driver_name,
(u32)netxen_decode_crb_addr(addr), 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)) {
/* 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 == (NETXEN_CRB_PEG_NET_1 + 0x18))
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;
}
if (off == NETXEN_ADDR_ERROR) {
printk(KERN_ERR "%s: Err: Unknown addr: 0x%08x\n",
netxen_nic_driver_name, buf[i].addr);
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);
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
int
netxen_load_firmware(struct netxen_adapter *adapter)
{
u64 *ptr64;
u32 i, flashaddr, size;
const struct firmware *fw = adapter->fw;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 1);
if (fw) {
__le64 data;
size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 8;
ptr64 = (u64 *)&fw->data[NETXEN_BOOTLD_START];
flashaddr = NETXEN_BOOTLD_START;
for (i = 0; i < size; i++) {
data = cpu_to_le64(ptr64[i]);
adapter->pci_mem_write(adapter, flashaddr, &data, 8);
flashaddr += 8;
}
size = *(u32 *)&fw->data[NX_FW_SIZE_OFFSET];
size = (__force u32)cpu_to_le32(size) / 8;
ptr64 = (u64 *)&fw->data[NETXEN_IMAGE_START];
flashaddr = NETXEN_IMAGE_START;
for (i = 0; i < size; i++) {
data = cpu_to_le64(ptr64[i]);
if (adapter->pci_mem_write(adapter,
flashaddr, &data, 8))
return -EIO;
flashaddr += 8;
}
} else {
u32 data;
size = (NETXEN_IMAGE_START - NETXEN_BOOTLD_START) / 4;
flashaddr = NETXEN_BOOTLD_START;
for (i = 0; i < size; i++) {
if (netxen_rom_fast_read(adapter,
flashaddr, (int *)&data) != 0)
return -EIO;
if (adapter->pci_mem_write(adapter,
flashaddr, &data, 4))
return -EIO;
flashaddr += 4;
}
}
msleep(1);
if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
NXWR32(adapter, NETXEN_ROMUSB_GLB_SW_RESET, 0x80001d);
else {
NXWR32(adapter, NETXEN_ROMUSB_GLB_CHIP_CLK_CTRL, 0x3fff);
NXWR32(adapter, NETXEN_ROMUSB_GLB_CAS_RST, 0);
}
return 0;
}
static int
netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname)
{
__le32 val;
struct pci_dev *pdev = adapter->pdev;
const struct firmware *fw = adapter->fw;
if (fw->size < NX_FW_MIN_SIZE)
return -EINVAL;
val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_MAGIC_OFFSET]);
if ((__force u32)val != NETXEN_BDINFO_MAGIC)
return -EINVAL;
val = cpu_to_le32(*(u32 *)&fw->data[NX_FW_VERSION_OFFSET]);
if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
min_ver = NETXEN_VERSION_CODE(4, 0, 216);
else
min_ver = NETXEN_VERSION_CODE(3, 4, 216);
if ((_major(ver) > _NETXEN_NIC_LINUX_MAJOR) || (ver < min_ver)) {
dev_err(&pdev->dev,
"%s: firmware version %d.%d.%d unsupported\n",
fwname, _major(ver), _minor(ver), _build(ver));
return -EINVAL;
}
val = cpu_to_le32(*(u32 *)&fw->data[NX_BIOS_VERSION_OFFSET]);
netxen_rom_fast_read(adapter, NX_BIOS_VERSION_OFFSET, (int *)&bios);
if ((__force u32)val != bios) {
dev_err(&pdev->dev, "%s: firmware bios is incompatible\n",
fwname);
return -EINVAL;
}
/* check if flashed firmware is newer */
if (netxen_rom_fast_read(adapter,
NX_FW_VERSION_OFFSET, (int *)&val))
return -EIO;
val = NETXEN_DECODE_VERSION(val);
if (val > ver) {
dev_info(&pdev->dev, "%s: firmware is older than flash\n",
fwname);
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
NXWR32(adapter, NETXEN_CAM_RAM(0x1fc), NETXEN_BDINFO_MAGIC);
return 0;
}
static char *fw_name[] = { "nxromimg.bin", "nx3fwct.bin", "nx3fwmn.bin" };
void netxen_request_firmware(struct netxen_adapter *adapter)
{
u32 capability, flashed_ver;
int fw_type;
struct pci_dev *pdev = adapter->pdev;
int rc = 0;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
fw_type = NX_P2_MN_ROMIMAGE;
goto request_fw;
} else {
fw_type = NX_P3_CT_ROMIMAGE;
goto request_fw;
}
request_mn:
capability = 0;
netxen_rom_fast_read(adapter,
NX_FW_VERSION_OFFSET, (int *)&flashed_ver);
flashed_ver = NETXEN_DECODE_VERSION(flashed_ver);
if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {
capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY);
if (capability & NX_PEG_TUNE_MN_PRESENT) {
fw_type = NX_P3_MN_ROMIMAGE;
goto request_fw;
}
}
adapter->fw = NULL;
goto done;
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
request_fw:
rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev);
if (rc != 0) {
if (fw_type == NX_P3_CT_ROMIMAGE) {
msleep(1);
goto request_mn;
}
adapter->fw = NULL;
goto done;
}
rc = netxen_validate_firmware(adapter, fw_name[fw_type]);
if (rc != 0) {
release_firmware(adapter->fw);
if (fw_type == NX_P3_CT_ROMIMAGE) {
msleep(1);
goto request_mn;
}
adapter->fw = NULL;
goto done;
}
done:
if (adapter->fw)
dev_info(&pdev->dev, "loading firmware from file %s\n",
fw_name[fw_type]);
else
dev_info(&pdev->dev, "loading firmware from flash\n");
}
void
netxen_release_firmware(struct netxen_adapter *adapter)
{
if (adapter->fw)
release_firmware(adapter->fw);
}
int netxen_initialize_adapter_offload(struct netxen_adapter *adapter)
{
uint64_t addr;
uint32_t hi;
uint32_t lo;
adapter->dummy_dma.addr =
pci_alloc_consistent(adapter->pdev,
NETXEN_HOST_DUMMY_DMA_SIZE,
&adapter->dummy_dma.phys_addr);
if (adapter->dummy_dma.addr == NULL) {
printk("%s: ERROR: Could not allocate dummy DMA memory\n",
return -ENOMEM;
}
addr = (uint64_t) adapter->dummy_dma.phys_addr;
hi = (addr >> 32) & 0xffffffff;
lo = addr & 0xffffffff;
NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_HI, hi);
NXWR32(adapter, CRB_HOST_DUMMY_BUF_ADDR_LO, lo);
if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
uint32_t temp = 0;
NXWR32(adapter, CRB_HOST_DUMMY_BUF, temp);
return 0;
}
void netxen_free_adapter_offload(struct netxen_adapter *adapter)
{
int i = 100;
if (!adapter->dummy_dma.addr)
return;
if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
do {
if (dma_watchdog_shutdown_request(adapter) == 1)
break;
msleep(50);
if (dma_watchdog_shutdown_poll_result(adapter) == 1)
break;
} while (--i);
if (i) {
pci_free_consistent(adapter->pdev,
NETXEN_HOST_DUMMY_DMA_SIZE,
adapter->dummy_dma.addr,
adapter->dummy_dma.phys_addr);
adapter->dummy_dma.addr = NULL;
} else {
printk(KERN_ERR "%s: dma_watchdog_shutdown failed\n",
adapter->netdev->name);
Dhananjay Phadke
committed
int netxen_phantom_init(struct netxen_adapter *adapter, int pegtune_val)
if (pegtune_val)
return 0;
do {
val = NXRD32(adapter, CRB_CMDPEG_STATE);
Dhananjay Phadke
committed
switch (val) {
case PHAN_INITIALIZE_COMPLETE:
case PHAN_INITIALIZE_ACK:
return 0;
case PHAN_INITIALIZE_FAILED:
goto out_err;
default:
break;
}
Dhananjay Phadke
committed
NXWR32(adapter, CRB_CMDPEG_STATE, PHAN_INITIALIZE_FAILED);
Dhananjay Phadke
committed
out_err:
dev_warn(&adapter->pdev->dev, "firmware init failed\n");
return -EIO;
static int
netxen_receive_peg_ready(struct netxen_adapter *adapter)
{
u32 val = 0;
int retries = 2000;
do {
val = NXRD32(adapter, CRB_RCVPEG_STATE);
if (val == PHAN_PEG_RCV_INITIALIZED)
return 0;
msleep(10);
} while (--retries);
if (!retries) {
printk(KERN_ERR "Receive Peg initialization not "
"complete, state: 0x%x.\n", val);
return -EIO;
}
return 0;
}