Added ethtool support for user level firmware management utilities.

Signed-off-by: Amit S. Kale <[EMAIL PROTECTED]>

---

 netxen_nic.h         |   16 ++-
 netxen_nic_ethtool.c |   87 +++++++++++++---
 netxen_nic_init.c    |  268 ++++++++++++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 351 insertions(+), 20 deletions(-)

diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 59324b1..f188b59 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -63,12 +63,16 @@ #include <asm/pgtable.h>
 
 #include "netxen_nic_hw.h"
 
-#define NETXEN_NIC_BUILD_NO     "2"
+#define NETXEN_NIC_BUILD_NO     "3"
 #define _NETXEN_NIC_LINUX_MAJOR 3
 #define _NETXEN_NIC_LINUX_MINOR 3
 #define _NETXEN_NIC_LINUX_SUBVERSION 3
 #define NETXEN_NIC_LINUX_VERSIONID  "3.3.3" "-" NETXEN_NIC_BUILD_NO
 
+#define NUM_FLASH_SECTORS (64)
+#define FLASH_SECTOR_SIZE (64*1024)
+#define FLASH_TOTAL_SIZE  (NUM_FLASH_SECTORS*FLASH_SECTOR_SIZE)
+
 #define RCV_DESC_RINGSIZE      \
        (sizeof(struct rcv_desc) * adapter->max_rx_desc_count)
 #define STATUS_DESC_RINGSIZE   \
@@ -85,6 +89,7 @@ #define NETXEN_NETDEV_STATUS          0x1
 #define NETXEN_RCV_PRODUCER_OFFSET     0
 #define NETXEN_RCV_PEG_DB_ID           2
 #define NETXEN_HOST_DUMMY_DMA_SIZE 1024
+#define FLASH_SUCCESS 0
 
 #define ADDR_IN_WINDOW1(off)   \
        ((off > NETXEN_CRB_PCIX_HOST2) && (off < NETXEN_CRB_MAX)) ? 1 : 0
@@ -1034,6 +1039,15 @@ void netxen_phantom_init(struct netxen_a
 void netxen_load_firmware(struct netxen_adapter *adapter);
 int netxen_pinit_from_rom(struct netxen_adapter *adapter, int verbose);
 int netxen_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp);
+int netxen_rom_fast_read_words(struct netxen_adapter *adapter, int addr, 
+                               u8 *bytes, size_t size);
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, 
+                               u8 *bytes, size_t size);
+int netxen_flash_unlock(struct netxen_adapter *adapter);
+int netxen_backup_crbinit(struct netxen_adapter *adapter);
+int netxen_flash_erase_secondary(struct netxen_adapter *adapter);
+int netxen_flash_erase_primary(struct netxen_adapter *adapter);
+
 int netxen_rom_fast_write(struct netxen_adapter *adapter, int addr, int data);
 int netxen_rom_se(struct netxen_adapter *adapter, int addr);
 int netxen_do_rom_se(struct netxen_adapter *adapter, int addr);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c 
b/drivers/net/netxen/netxen_nic_ethtool.c
index 3404461..49b3b4c 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -32,6 +32,7 @@
  */
 
 #include <linux/types.h>
+#include <linux/delay.h>
 #include <asm/uaccess.h>
 #include <linux/pci.h>
 #include <asm/io.h>
@@ -94,17 +95,7 @@ #define NETXEN_MAX_EEPROM_LEN   1024
 
 static int netxen_nic_get_eeprom_len(struct net_device *dev)
 {
-       struct netxen_port *port = netdev_priv(dev);
-       struct netxen_adapter *adapter = port->adapter;
-       int n;
-
-       if ((netxen_rom_fast_read(adapter, 0, &n) == 0)
-           && (n & NETXEN_ROM_ROUNDUP)) {
-               n &= ~NETXEN_ROM_ROUNDUP;
-               if (n < NETXEN_MAX_EEPROM_LEN)
-                       return n;
-       }
-       return 0;
+       return FLASH_TOTAL_SIZE;
 }
 
 static void
@@ -445,13 +436,78 @@ netxen_nic_get_eeprom(struct net_device 
                return -EINVAL;
 
        eeprom->magic = (port->pdev)->vendor | ((port->pdev)->device << 16);
-       for (offset = 0; offset < eeprom->len; offset++)
-               if (netxen_rom_fast_read
-                   (adapter, (8 * offset) + 8, (int *)eeprom->data) == -1)
-                       return -EIO;
+       offset = eeprom->offset;
+
+       if (netxen_rom_fast_read_words
+               (adapter, offset, bytes, eeprom->len) == -1){
+               return -EIO;
+       }
+
        return 0;
 }
 
+static int
+netxen_nic_set_eeprom(struct net_device *dev, struct ethtool_eeprom *eeprom,
+                       u8 * bytes)
+{
+       struct netxen_port *port = netdev_priv(dev);
+       struct netxen_adapter *adapter = port->adapter;
+       int offset = eeprom->offset;
+       static int first_write = 1;
+       int ret;
+       static int ready_to_flash = 0;
+
+       if(first_write == 1){
+               netxen_flash_unlock(adapter);
+               printk("%s: flash unlocked. \n", netxen_nic_driver_name);
+               if ((ret = netxen_flash_erase_secondary(adapter)) 
+                       != FLASH_SUCCESS) {
+                       printk("%s: Flash erase failed.\n", 
+                               netxen_nic_driver_name);
+                       return(ret);
+               }
+               printk("%s: secondary flash erased successfully.\n", 
+                       netxen_nic_driver_name);
+               first_write = 0;
+               return 0;
+       }
+
+       if(offset == BOOTLD_START){
+               if ((ret = netxen_flash_erase_primary(adapter)) 
+                       != FLASH_SUCCESS) {
+                       printk("%s: Flash erase failed.\n", 
+                               netxen_nic_driver_name);
+                       return ret;
+               }
+               if((ret = netxen_rom_se(adapter, USER_START)) != FLASH_SUCCESS)
+                       return ret;
+               if((ret = netxen_rom_se(adapter, FIXED_START)) != FLASH_SUCCESS)
+                       return ret;
+               printk("%s: primary flash erased successfully\n", 
+                       netxen_nic_driver_name);
+               udelay (500);
+
+               if((ret = netxen_backup_crbinit(adapter)) != FLASH_SUCCESS){
+                       printk("%s: CRBinit backup failed.\n", 
+                               netxen_nic_driver_name);
+                       return ret;
+               }
+               printk("%s: CRBinit backup done.\n", netxen_nic_driver_name);
+               ready_to_flash = 1;
+               udelay (500);
+       }
+
+       if(!ready_to_flash){
+               printk("%s: Invalid write sequence, returning...\n",
+                       netxen_nic_driver_name);
+               return -EINVAL;
+       }
+
+       udelay (500);
+
+       return netxen_rom_fast_write_words(adapter, offset, bytes, eeprom->len);
+}
+
 static void
 netxen_nic_get_ringparam(struct net_device *dev, struct ethtool_ringparam 
*ring)
 {
@@ -721,6 +777,7 @@ struct ethtool_ops netxen_nic_ethtool_op
        .get_link = netxen_nic_get_link,
        .get_eeprom_len = netxen_nic_get_eeprom_len,
        .get_eeprom = netxen_nic_get_eeprom,
+       .set_eeprom = netxen_nic_set_eeprom,
        .get_ringparam = netxen_nic_get_ringparam,
        .get_pauseparam = netxen_nic_get_pauseparam,
        .set_pauseparam = netxen_nic_set_pauseparam,
diff --git a/drivers/net/netxen/netxen_nic_init.c 
b/drivers/net/netxen/netxen_nic_init.c
index c3e41f3..069436f 100644
--- a/drivers/net/netxen/netxen_nic_init.c
+++ b/drivers/net/netxen/netxen_nic_init.c
@@ -391,6 +391,7 @@ static inline int do_rom_fast_write(stru
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE,
                             M25P_INSTR_PP);
+       udelay(100);
        if (netxen_wait_rom_done(adapter)) {
                netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
                return -1;
@@ -399,12 +400,13 @@ static inline int do_rom_fast_write(stru
        return netxen_rom_wip_poll(adapter);
 }
 
+
 static inline int
 do_rom_fast_read(struct netxen_adapter *adapter, int addr, int *valp)
 {
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
-       udelay(100);            /* prevent bursting on CRB */
+       udelay(70);             /* prevent bursting on CRB */
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 0xb);
        if (netxen_wait_rom_done(adapter)) {
@@ -413,13 +415,45 @@ do_rom_fast_read(struct netxen_adapter *
        }
        /* reset abyte_cnt and dummy_byte_cnt */
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
-       udelay(100);            /* prevent bursting on CRB */
+       udelay(70);             /* prevent bursting on CRB */
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_DUMMY_BYTE_CNT, 0);
 
        *valp = netxen_nic_reg_read(adapter, NETXEN_ROMUSB_ROM_RDATA);
        return 0;
 }
 
+static inline int 
+do_rom_fast_read_words(struct netxen_adapter *adapter, int addr,
+                       u8 *bytes, size_t size)
+{
+       int addridx = addr;
+       int ret = 0;
+
+       while (addridx < (addr + size)) {
+               ret = do_rom_fast_read(adapter, addridx, (int *)bytes);
+               if(ret != 0)
+                       break;
+               bytes += 4;
+               addridx += 4;
+       }
+       return ret;
+}
+
+int
+netxen_rom_fast_read_words (struct netxen_adapter *adapter, int addr, u8 
*bytes, 
+                       size_t size)
+{
+       int ret;
+       if (rom_lock(adapter) != 0) {
+               return -1;
+       }
+
+       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;
@@ -443,20 +477,189 @@ int netxen_rom_fast_write(struct netxen_
        netxen_rom_unlock(adapter);
        return ret;
 }
+
+static inline int do_rom_fast_write_words(struct netxen_adapter *adapter, 
+                                               int addr, u8 *bytes, size_t 
size)
+{
+       int addridx = addr;
+       int data1;
+       int data;
+       int ret = 0;
+       int timeout = 0;
+
+       while (addridx < (addr + size)) {
+               data = *(u32*)bytes;
+
+               ret = do_rom_fast_write(adapter, addridx, data);
+               if(ret == -1){
+                       printk("do_rom_fast_write returned error \n");
+                       return ret;
+                       
+               }
+               timeout = 0;
+
+               while(1){
+                       do_rom_fast_read(adapter, addridx, &data1);
+
+                       if(data1 == data){
+                               break;
+                       }
+
+                       if(timeout++ >= 300) {
+                               printk("netxen_nic: Data write didn't succeed"
+                                       " at address %x\n", addridx);
+                               break;
+                       }
+               }
+
+               bytes += 4;
+               addridx += 4;
+       }
+
+       return ret;
+}
+
+int netxen_rom_fast_write_words(struct netxen_adapter *adapter, int addr, 
+                                       u8 *bytes, size_t size)
+{
+       int ret = 0;
+
+       if (rom_lock(adapter) != 0) {
+               return -EAGAIN;
+       }
+
+       ret = do_rom_fast_write_words(adapter, addr, bytes, size);
+       netxen_rom_unlock(adapter);
+       return ret;
+}
+
+int netxen_rom_wrsr(struct netxen_adapter *adapter, int data)
+{
+       if (netxen_rom_wren(adapter)){
+               return -1;
+       }
+       netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_WDATA, data);
+       netxen_crb_writelit_adapter(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE, 
0x1);
+
+       if (netxen_wait_rom_done(adapter)) {
+               return -1;
+       }
+       return netxen_rom_wip_poll(adapter);
+}
+
+int netxen_rom_rdsr(struct netxen_adapter *adapter)
+{
+       int ret;
+
+       if (rom_lock(adapter) != 0){
+               return -1;
+       }
+       ret = netxen_do_rom_rdsr(adapter);
+       netxen_rom_unlock(adapter);
+       return ret;
+}
+
+int netxen_backup_crbinit(struct netxen_adapter *adapter)
+{
+       int ret = FLASH_SUCCESS;
+       int val;
+       char *buffer = kmalloc(FLASH_SECTOR_SIZE, GFP_KERNEL);
+
+       /* unlock sector 63 */
+       val = netxen_rom_rdsr(adapter);
+       val = val & 0xe3;
+       ret = netxen_rom_wrsr(adapter, val);
+       if(ret != FLASH_SUCCESS){
+               kfree(buffer);
+               return -1;
+       }
+       ret = netxen_rom_wip_poll(adapter);
+       if(ret != FLASH_SUCCESS){
+               kfree(buffer);
+               return -1;
+       }
+       /* copy  sector 0 to sector 63 */
+
+       if (netxen_rom_fast_read_words
+               (adapter, CRBINIT_START, buffer, FLASH_SECTOR_SIZE) == -1){
+               printk("get_eeprom() fails...\n");
+               kfree(buffer);
+               return -EIO;
+       }
+
+       ret = netxen_rom_fast_write_words(adapter, FIXED_START, buffer,
+                                          FLASH_SECTOR_SIZE);
+       if(ret != FLASH_SUCCESS){
+               kfree(buffer);
+               return -1;
+       }
+
+       /* lock sector 63 */
+       val = netxen_rom_rdsr(adapter);
+       if (!(val & 0x8)) {
+               val |= (0x1 << 2);
+               /* lock sector 63 */
+               if (netxen_rom_wrsr(adapter, val) == 0) {
+                       ret = netxen_rom_wip_poll(adapter);
+                       if(ret != FLASH_SUCCESS){
+                               kfree(buffer);
+                               return -1;
+                       }
+                       /* lock SR writes */
+                       val = val | 0x80;
+                       ret = netxen_rom_wip_poll(adapter);
+                       if(ret != FLASH_SUCCESS){
+                               kfree(buffer);
+                               return -1;
+                       }
+               }
+       }
+       kfree(buffer);
+       return ret;
+}
+
 int netxen_do_rom_se(struct netxen_adapter *adapter, int addr)
 {
-       netxen_rom_wren(adapter);
+       if(netxen_rom_wren(adapter) != 0)
+               return -1;
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ADDRESS, addr);
+       udelay(200);
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 3);
+       udelay(200);
        netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_INSTR_OPCODE,
-                            M25P_INSTR_SE);
+                               M25P_INSTR_SE);
+       udelay(200);
        if (netxen_wait_rom_done(adapter)) {
                netxen_nic_reg_write(adapter, NETXEN_ROMUSB_ROM_ABYTE_CNT, 0);
                return -1;
        }
+
        return netxen_rom_wip_poll(adapter);
 }
 
+void check_erased_flash(struct netxen_adapter *adapter, int addr)
+{
+       int i;
+       int val;
+       int count = 0, erased_errors =0;
+       int range;
+
+       if(addr == 0x3e8000)
+               range = 0x3f0000;       
+       else range = addr + FLASH_SECTOR_SIZE;
+       
+       for(i = addr; i < range; i+=4){
+               netxen_rom_fast_read(adapter, i, &val);
+               if(val != 0xffffffff)
+                       erased_errors++;
+               count++;
+       }
+
+       if(erased_errors)
+               printk("0x%x out of 0x%x words fail to be erased "
+                       "for sector address: %x\n", erased_errors, count, addr);
+
+}
 int netxen_rom_se(struct netxen_adapter *adapter, int addr)
 {
        int ret = 0;
@@ -465,6 +668,63 @@ int netxen_rom_se(struct netxen_adapter 
        }
        ret = netxen_do_rom_se(adapter, addr);
        netxen_rom_unlock(adapter);
+       schedule();
+       check_erased_flash(adapter, addr);
+       return ret;
+}
+
+int
+netxen_flash_erase_sections(struct netxen_adapter *adapter, int start, int end)
+{
+       int ret = FLASH_SUCCESS;
+       int i;
+       for (i = start; i < end; i++) {
+               ret = netxen_rom_se(adapter, i*FLASH_SECTOR_SIZE);
+               if (ret)
+                       break;
+               if (netxen_rom_wip_poll(adapter) != 0) {
+                       ret = -1;
+                       break;
+               }
+       }
+       return(ret);
+}
+
+int
+netxen_flash_erase_secondary(struct netxen_adapter *adapter)
+{
+       int ret = FLASH_SUCCESS;
+       int start, end;
+
+       start = SECONDARY_START/FLASH_SECTOR_SIZE;
+       end   = USER_START/FLASH_SECTOR_SIZE;
+       netxen_flash_erase_sections(adapter, start, end);
+
+       return(ret);
+}
+
+int
+netxen_flash_erase_primary(struct netxen_adapter *adapter)
+{
+       int ret = FLASH_SUCCESS;
+       int start, end;
+
+       start = PRIMARY_START/FLASH_SECTOR_SIZE;
+       end   = SECONDARY_START/FLASH_SECTOR_SIZE;
+       ret = netxen_flash_erase_sections(adapter, start, end);
+
+       return(ret);
+}
+
+int netxen_flash_unlock(struct netxen_adapter *adapter)
+{
+       int ret = 0;
+
+       if (netxen_rom_wrsr(adapter, 0) != 0)
+               ret = -1;
+       if (netxen_rom_wren(adapter) != 0)
+               ret = -1;
+
        return ret;
 }
 
-
To unsubscribe from this list: send the line "unsubscribe netdev" in
the body of a message to [EMAIL PROTECTED]
More majordomo info at  http://vger.kernel.org/majordomo-info.html

Reply via email to