bna: Added flash sub-module and ethtool eeprom entry points.
Krishna Gudipati [Thu, 22 Dec 2011 13:29:45 +0000 (13:29 +0000)]
Change details:
- The patch adds flash sub-module to the bna driver.
- Added ethtool set_eeprom() and get_eeprom() entry points to
  support flash partition read/write operations.

Signed-off-by: Krishna Gudipati <kgudipat@brocade.com>
Signed-off-by: David S. Miller <davem@davemloft.net>

drivers/net/ethernet/brocade/bna/bfa_defs.h
drivers/net/ethernet/brocade/bna/bfa_ioc.c
drivers/net/ethernet/brocade/bna/bfa_ioc.h
drivers/net/ethernet/brocade/bna/bfi.h
drivers/net/ethernet/brocade/bna/bna_enet.c
drivers/net/ethernet/brocade/bna/bna_types.h
drivers/net/ethernet/brocade/bna/bnad.c
drivers/net/ethernet/brocade/bna/bnad.h
drivers/net/ethernet/brocade/bna/bnad_ethtool.c

index 2f12d68..871c630 100644 (file)
@@ -219,41 +219,39 @@ enum {
  * All numerical fields are in big-endian format.
  */
 struct bfa_mfg_block {
-       u8              version;        /*!< manufacturing block version */
-       u8              mfg_sig[3];     /*!< characters 'M', 'F', 'G' */
-       u16     mfgsize;        /*!< mfg block size */
-       u16     u16_chksum;     /*!< old u16 checksum */
-       char            brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
-       char            brcd_partnum[STRSZ(BFA_MFG_PARTNUM_SIZE)];
-       u8              mfg_day;        /*!< manufacturing day */
-       u8              mfg_month;      /*!< manufacturing month */
-       u16     mfg_year;       /*!< manufacturing year */
-       u64             mfg_wwn;        /*!< wwn base for this adapter */
-       u8              num_wwn;        /*!< number of wwns assigned */
-       u8              mfg_speeds;     /*!< speeds allowed for this adapter */
-       u8              rsv[2];
-       char            supplier_id[STRSZ(BFA_MFG_SUPPLIER_ID_SIZE)];
-       char            supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)];
-       char
-               supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)];
-       char
-               supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)];
-       mac_t           mfg_mac;        /*!< mac address */
-       u8              num_mac;        /*!< number of mac addresses */
-       u8              rsv2;
-       u32             card_type;      /*!< card type */
-       char            cap_nic;        /*!< capability nic */
-       char            cap_cna;        /*!< capability cna */
-       char            cap_hba;        /*!< capability hba */
-       char            cap_fc16g;      /*!< capability fc 16g */
-       char            cap_sriov;      /*!< capability sriov */
-       char            cap_mezz;       /*!< capability mezz */
-       u8              rsv3;
-       u8              mfg_nports;     /*!< number of ports */
-       char            media[8];       /*!< xfi/xaui */
-       char            initial_mode[8];/*!< initial mode: hba/cna/nic */
-       u8              rsv4[84];
-       u8              md5_chksum[BFA_MFG_CHKSUM_SIZE]; /*!< md5 checksum */
+       u8      version;        /* manufacturing block version */
+       u8      mfg_sig[3];     /* characters 'M', 'F', 'G' */
+       u16     mfgsize;        /* mfg block size */
+       u16     u16_chksum;     /* old u16 checksum */
+       char    brcd_serialnum[STRSZ(BFA_MFG_SERIALNUM_SIZE)];
+       char    brcd_partnum[STRSZ(BFA_MFG_PARTNUM_SIZE)];
+       u8      mfg_day;        /* manufacturing day */
+       u8      mfg_month;      /* manufacturing month */
+       u16     mfg_year;       /* manufacturing year */
+       u64     mfg_wwn;        /* wwn base for this adapter */
+       u8      num_wwn;        /* number of wwns assigned */
+       u8      mfg_speeds;     /* speeds allowed for this adapter */
+       u8      rsv[2];
+       char    supplier_id[STRSZ(BFA_MFG_SUPPLIER_ID_SIZE)];
+       char    supplier_partnum[STRSZ(BFA_MFG_SUPPLIER_PARTNUM_SIZE)];
+       char    supplier_serialnum[STRSZ(BFA_MFG_SUPPLIER_SERIALNUM_SIZE)];
+       char    supplier_revision[STRSZ(BFA_MFG_SUPPLIER_REVISION_SIZE)];
+       mac_t   mfg_mac;        /* base mac address */
+       u8      num_mac;        /* number of mac addresses */
+       u8      rsv2;
+       u32     card_type;      /* card type          */
+       char    cap_nic;        /* capability nic     */
+       char    cap_cna;        /* capability cna     */
+       char    cap_hba;        /* capability hba     */
+       char    cap_fc16g;      /* capability fc 16g      */
+       char    cap_sriov;      /* capability sriov       */
+       char    cap_mezz;       /* capability mezz        */
+       u8      rsv3;
+       u8      mfg_nports;     /* number of ports        */
+       char    media[8];       /* xfi/xaui           */
+       char    initial_mode[8]; /* initial mode: hba/cna/nic */
+       u8      rsv4[84];
+       u8      md5_chksum[BFA_MFG_CHKSUM_SIZE]; /* md5 checksum */
 };
 
 #pragma pack()
@@ -293,4 +291,34 @@ enum bfa_mode {
        BFA_MODE_NIC            = 3
 };
 
+/*
+ *     Flash module specific
+ */
+#define BFA_FLASH_PART_ENTRY_SIZE      32      /* partition entry size */
+#define BFA_FLASH_PART_MAX             32      /* maximal # of partitions */
+#define BFA_TOTAL_FLASH_SIZE           0x400000
+#define BFA_FLASH_PART_MFG             7
+
+/*
+ * flash partition attributes
+ */
+struct bfa_flash_part_attr {
+       u32     part_type;      /* partition type */
+       u32     part_instance;  /* partition instance */
+       u32     part_off;       /* partition offset */
+       u32     part_size;      /* partition size */
+       u32     part_len;       /* partition content length */
+       u32     part_status;    /* partition status */
+       char    rsv[BFA_FLASH_PART_ENTRY_SIZE - 24];
+};
+
+/*
+ * flash attributes
+ */
+struct bfa_flash_attr {
+       u32     status; /* flash overall status */
+       u32     npart;  /* num of partitions */
+       struct bfa_flash_part_attr part[BFA_FLASH_PART_MAX];
+};
+
 #endif /* __BFA_DEFS_H__ */
index b0307a0..1d13044 100644 (file)
@@ -2172,6 +2172,15 @@ bfa_nw_ioc_is_disabled(struct bfa_ioc *ioc)
 }
 
 /**
+ * return true if IOC is operational
+ */
+bool
+bfa_nw_ioc_is_operational(struct bfa_ioc *ioc)
+{
+       return bfa_fsm_cmp_state(ioc, bfa_ioc_sm_op);
+}
+
+/**
  * Add to IOC heartbeat failure notification queue. To be used by common
  * modules such as cee, port, diag.
  */
@@ -2471,3 +2480,366 @@ bfa_ioc_poll_fwinit(struct bfa_ioc *ioc)
                        msecs_to_jiffies(BFA_IOC_POLL_TOV));
        }
 }
+
+/*
+ *     Flash module specific
+ */
+
+/*
+ * FLASH DMA buffer should be big enough to hold both MFG block and
+ * asic block(64k) at the same time and also should be 2k aligned to
+ * avoid write segement to cross sector boundary.
+ */
+#define BFA_FLASH_SEG_SZ       2048
+#define BFA_FLASH_DMA_BUF_SZ   \
+       roundup(0x010000 + sizeof(struct bfa_mfg_block), BFA_FLASH_SEG_SZ)
+
+static void
+bfa_flash_cb(struct bfa_flash *flash)
+{
+       flash->op_busy = 0;
+       if (flash->cbfn)
+               flash->cbfn(flash->cbarg, flash->status);
+}
+
+static void
+bfa_flash_notify(void *cbarg, enum bfa_ioc_event event)
+{
+       struct bfa_flash *flash = cbarg;
+
+       switch (event) {
+       case BFA_IOC_E_DISABLED:
+       case BFA_IOC_E_FAILED:
+               if (flash->op_busy) {
+                       flash->status = BFA_STATUS_IOC_FAILURE;
+                       flash->cbfn(flash->cbarg, flash->status);
+                       flash->op_busy = 0;
+               }
+               break;
+       default:
+               break;
+       }
+}
+
+/*
+ * Send flash write request.
+ *
+ * @param[in] cbarg - callback argument
+ */
+static void
+bfa_flash_write_send(struct bfa_flash *flash)
+{
+       struct bfi_flash_write_req *msg =
+                       (struct bfi_flash_write_req *) flash->mb.msg;
+       u32     len;
+
+       msg->type = be32_to_cpu(flash->type);
+       msg->instance = flash->instance;
+       msg->offset = be32_to_cpu(flash->addr_off + flash->offset);
+       len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ?
+              flash->residue : BFA_FLASH_DMA_BUF_SZ;
+       msg->length = be32_to_cpu(len);
+
+       /* indicate if it's the last msg of the whole write operation */
+       msg->last = (len == flash->residue) ? 1 : 0;
+
+       bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_WRITE_REQ,
+                   bfa_ioc_portid(flash->ioc));
+       bfa_alen_set(&msg->alen, len, flash->dbuf_pa);
+       memcpy(flash->dbuf_kva, flash->ubuf + flash->offset, len);
+       bfa_nw_ioc_mbox_queue(flash->ioc, &flash->mb, NULL, NULL);
+
+       flash->residue -= len;
+       flash->offset += len;
+}
+
+/*
+ * Send flash read request.
+ *
+ * @param[in] cbarg - callback argument
+ */
+static void
+bfa_flash_read_send(void *cbarg)
+{
+       struct bfa_flash *flash = cbarg;
+       struct bfi_flash_read_req *msg =
+                       (struct bfi_flash_read_req *) flash->mb.msg;
+       u32     len;
+
+       msg->type = be32_to_cpu(flash->type);
+       msg->instance = flash->instance;
+       msg->offset = be32_to_cpu(flash->addr_off + flash->offset);
+       len = (flash->residue < BFA_FLASH_DMA_BUF_SZ) ?
+              flash->residue : BFA_FLASH_DMA_BUF_SZ;
+       msg->length = be32_to_cpu(len);
+       bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_READ_REQ,
+                   bfa_ioc_portid(flash->ioc));
+       bfa_alen_set(&msg->alen, len, flash->dbuf_pa);
+       bfa_nw_ioc_mbox_queue(flash->ioc, &flash->mb, NULL, NULL);
+}
+
+/*
+ * Process flash response messages upon receiving interrupts.
+ *
+ * @param[in] flasharg - flash structure
+ * @param[in] msg - message structure
+ */
+static void
+bfa_flash_intr(void *flasharg, struct bfi_mbmsg *msg)
+{
+       struct bfa_flash *flash = flasharg;
+       u32     status;
+
+       union {
+               struct bfi_flash_query_rsp *query;
+               struct bfi_flash_write_rsp *write;
+               struct bfi_flash_read_rsp *read;
+               struct bfi_mbmsg   *msg;
+       } m;
+
+       m.msg = msg;
+
+       /* receiving response after ioc failure */
+       if (!flash->op_busy && msg->mh.msg_id != BFI_FLASH_I2H_EVENT)
+               return;
+
+       switch (msg->mh.msg_id) {
+       case BFI_FLASH_I2H_QUERY_RSP:
+               status = be32_to_cpu(m.query->status);
+               if (status == BFA_STATUS_OK) {
+                       u32     i;
+                       struct bfa_flash_attr *attr, *f;
+
+                       attr = (struct bfa_flash_attr *) flash->ubuf;
+                       f = (struct bfa_flash_attr *) flash->dbuf_kva;
+                       attr->status = be32_to_cpu(f->status);
+                       attr->npart = be32_to_cpu(f->npart);
+                       for (i = 0; i < attr->npart; i++) {
+                               attr->part[i].part_type =
+                                       be32_to_cpu(f->part[i].part_type);
+                               attr->part[i].part_instance =
+                                       be32_to_cpu(f->part[i].part_instance);
+                               attr->part[i].part_off =
+                                       be32_to_cpu(f->part[i].part_off);
+                               attr->part[i].part_size =
+                                       be32_to_cpu(f->part[i].part_size);
+                               attr->part[i].part_len =
+                                       be32_to_cpu(f->part[i].part_len);
+                               attr->part[i].part_status =
+                                       be32_to_cpu(f->part[i].part_status);
+                       }
+               }
+               flash->status = status;
+               bfa_flash_cb(flash);
+               break;
+       case BFI_FLASH_I2H_WRITE_RSP:
+               status = be32_to_cpu(m.write->status);
+               if (status != BFA_STATUS_OK || flash->residue == 0) {
+                       flash->status = status;
+                       bfa_flash_cb(flash);
+               } else
+                       bfa_flash_write_send(flash);
+               break;
+       case BFI_FLASH_I2H_READ_RSP:
+               status = be32_to_cpu(m.read->status);
+               if (status != BFA_STATUS_OK) {
+                       flash->status = status;
+                       bfa_flash_cb(flash);
+               } else {
+                       u32 len = be32_to_cpu(m.read->length);
+                       memcpy(flash->ubuf + flash->offset,
+                              flash->dbuf_kva, len);
+                       flash->residue -= len;
+                       flash->offset += len;
+                       if (flash->residue == 0) {
+                               flash->status = status;
+                               bfa_flash_cb(flash);
+                       } else
+                               bfa_flash_read_send(flash);
+               }
+               break;
+       case BFI_FLASH_I2H_BOOT_VER_RSP:
+       case BFI_FLASH_I2H_EVENT:
+               break;
+       default:
+               WARN_ON(1);
+       }
+}
+
+/*
+ * Flash memory info API.
+ */
+u32
+bfa_nw_flash_meminfo(void)
+{
+       return roundup(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
+}
+
+/*
+ * Flash attach API.
+ *
+ * @param[in] flash - flash structure
+ * @param[in] ioc  - ioc structure
+ * @param[in] dev  - device structure
+ */
+void
+bfa_nw_flash_attach(struct bfa_flash *flash, struct bfa_ioc *ioc, void *dev)
+{
+       flash->ioc = ioc;
+       flash->cbfn = NULL;
+       flash->cbarg = NULL;
+       flash->op_busy = 0;
+
+       bfa_nw_ioc_mbox_regisr(flash->ioc, BFI_MC_FLASH, bfa_flash_intr, flash);
+       bfa_q_qe_init(&flash->ioc_notify);
+       bfa_ioc_notify_init(&flash->ioc_notify, bfa_flash_notify, flash);
+       list_add_tail(&flash->ioc_notify.qe, &flash->ioc->notify_q);
+}
+
+/*
+ * Claim memory for flash
+ *
+ * @param[in] flash - flash structure
+ * @param[in] dm_kva - pointer to virtual memory address
+ * @param[in] dm_pa - physical memory address
+ */
+void
+bfa_nw_flash_memclaim(struct bfa_flash *flash, u8 *dm_kva, u64 dm_pa)
+{
+       flash->dbuf_kva = dm_kva;
+       flash->dbuf_pa = dm_pa;
+       memset(flash->dbuf_kva, 0, BFA_FLASH_DMA_BUF_SZ);
+       dm_kva += roundup(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
+       dm_pa += roundup(BFA_FLASH_DMA_BUF_SZ, BFA_DMA_ALIGN_SZ);
+}
+
+/*
+ * Get flash attribute.
+ *
+ * @param[in] flash - flash structure
+ * @param[in] attr - flash attribute structure
+ * @param[in] cbfn - callback function
+ * @param[in] cbarg - callback argument
+ *
+ * Return status.
+ */
+enum bfa_status
+bfa_nw_flash_get_attr(struct bfa_flash *flash, struct bfa_flash_attr *attr,
+                     bfa_cb_flash cbfn, void *cbarg)
+{
+       struct bfi_flash_query_req *msg =
+                       (struct bfi_flash_query_req *) flash->mb.msg;
+
+       if (!bfa_nw_ioc_is_operational(flash->ioc))
+               return BFA_STATUS_IOC_NON_OP;
+
+       if (flash->op_busy)
+               return BFA_STATUS_DEVBUSY;
+
+       flash->op_busy = 1;
+       flash->cbfn = cbfn;
+       flash->cbarg = cbarg;
+       flash->ubuf = (u8 *) attr;
+
+       bfi_h2i_set(msg->mh, BFI_MC_FLASH, BFI_FLASH_H2I_QUERY_REQ,
+                   bfa_ioc_portid(flash->ioc));
+       bfa_alen_set(&msg->alen, sizeof(struct bfa_flash_attr), flash->dbuf_pa);
+       bfa_nw_ioc_mbox_queue(flash->ioc, &flash->mb, NULL, NULL);
+
+       return BFA_STATUS_OK;
+}
+
+/*
+ * Update flash partition.
+ *
+ * @param[in] flash - flash structure
+ * @param[in] type - flash partition type
+ * @param[in] instance - flash partition instance
+ * @param[in] buf - update data buffer
+ * @param[in] len - data buffer length
+ * @param[in] offset - offset relative to the partition starting address
+ * @param[in] cbfn - callback function
+ * @param[in] cbarg - callback argument
+ *
+ * Return status.
+ */
+enum bfa_status
+bfa_nw_flash_update_part(struct bfa_flash *flash, u32 type, u8 instance,
+                        void *buf, u32 len, u32 offset,
+                        bfa_cb_flash cbfn, void *cbarg)
+{
+       if (!bfa_nw_ioc_is_operational(flash->ioc))
+               return BFA_STATUS_IOC_NON_OP;
+
+       /*
+        * 'len' must be in word (4-byte) boundary
+        */
+       if (!len || (len & 0x03))
+               return BFA_STATUS_FLASH_BAD_LEN;
+
+       if (type == BFA_FLASH_PART_MFG)
+               return BFA_STATUS_EINVAL;
+
+       if (flash->op_busy)
+               return BFA_STATUS_DEVBUSY;
+
+       flash->op_busy = 1;
+       flash->cbfn = cbfn;
+       flash->cbarg = cbarg;
+       flash->type = type;
+       flash->instance = instance;
+       flash->residue = len;
+       flash->offset = 0;
+       flash->addr_off = offset;
+       flash->ubuf = buf;
+
+       bfa_flash_write_send(flash);
+
+       return BFA_STATUS_OK;
+}
+
+/*
+ * Read flash partition.
+ *
+ * @param[in] flash - flash structure
+ * @param[in] type - flash partition type
+ * @param[in] instance - flash partition instance
+ * @param[in] buf - read data buffer
+ * @param[in] len - data buffer length
+ * @param[in] offset - offset relative to the partition starting address
+ * @param[in] cbfn - callback function
+ * @param[in] cbarg - callback argument
+ *
+ * Return status.
+ */
+enum bfa_status
+bfa_nw_flash_read_part(struct bfa_flash *flash, u32 type, u8 instance,
+                      void *buf, u32 len, u32 offset,
+                      bfa_cb_flash cbfn, void *cbarg)
+{
+       if (!bfa_nw_ioc_is_operational(flash->ioc))
+               return BFA_STATUS_IOC_NON_OP;
+
+       /*
+        * 'len' must be in word (4-byte) boundary
+        */
+       if (!len || (len & 0x03))
+               return BFA_STATUS_FLASH_BAD_LEN;
+
+       if (flash->op_busy)
+               return BFA_STATUS_DEVBUSY;
+
+       flash->op_busy = 1;
+       flash->cbfn = cbfn;
+       flash->cbarg = cbarg;
+       flash->type = type;
+       flash->instance = instance;
+       flash->residue = len;
+       flash->offset = 0;
+       flash->addr_off = offset;
+       flash->ubuf = buf;
+
+       bfa_flash_read_send(flash);
+
+       return BFA_STATUS_OK;
+}
index ca158d1..fc108c7 100644 (file)
@@ -68,6 +68,16 @@ __bfa_dma_be_addr_set(union bfi_addr_u *dma_addr, u64 pa)
        dma_addr->a32.addr_hi = (u32) htonl(upper_32_bits(pa));
 }
 
+#define bfa_alen_set(__alen, __len, __pa)      \
+       __bfa_alen_set(__alen, __len, (u64)__pa)
+
+static inline void
+__bfa_alen_set(struct bfi_alen *alen, u32 len, u64 pa)
+{
+       alen->al_len = cpu_to_be32(len);
+       bfa_dma_be_addr_set(alen->al_addr, pa);
+}
+
 struct bfa_ioc_regs {
        void __iomem *hfn_mbox_cmd;
        void __iomem *hfn_mbox;
@@ -322,4 +332,42 @@ void bfa_nw_iocpf_sem_timeout(void *ioc);
 u32 *bfa_cb_image_get_chunk(enum bfi_asic_gen asic_gen, u32 off);
 u32 bfa_cb_image_get_size(enum bfi_asic_gen asic_gen);
 
+/*
+ *     Flash module specific
+ */
+typedef void   (*bfa_cb_flash) (void *cbarg, enum bfa_status status);
+
+struct bfa_flash {
+       struct bfa_ioc *ioc;            /* back pointer to ioc */
+       u32             type;           /* partition type */
+       u8              instance;       /* partition instance */
+       u8              rsv[3];
+       u32             op_busy;        /*  operation busy flag */
+       u32             residue;        /*  residual length */
+       u32             offset;         /*  offset */
+       enum bfa_status status;         /*  status */
+       u8              *dbuf_kva;      /*  dma buf virtual address */
+       u64             dbuf_pa;        /*  dma buf physical address */
+       bfa_cb_flash    cbfn;           /*  user callback function */
+       void            *cbarg;         /*  user callback arg */
+       u8              *ubuf;          /*  user supplied buffer */
+       u32             addr_off;       /*  partition address offset */
+       struct bfa_mbox_cmd mb;         /*  mailbox */
+       struct bfa_ioc_notify ioc_notify; /*  ioc event notify */
+};
+
+enum bfa_status bfa_nw_flash_get_attr(struct bfa_flash *flash,
+                       struct bfa_flash_attr *attr,
+                       bfa_cb_flash cbfn, void *cbarg);
+enum bfa_status bfa_nw_flash_update_part(struct bfa_flash *flash,
+                       u32 type, u8 instance, void *buf, u32 len, u32 offset,
+                       bfa_cb_flash cbfn, void *cbarg);
+enum bfa_status bfa_nw_flash_read_part(struct bfa_flash *flash,
+                       u32 type, u8 instance, void *buf, u32 len, u32 offset,
+                       bfa_cb_flash cbfn, void *cbarg);
+u32    bfa_nw_flash_meminfo(void);
+void   bfa_nw_flash_attach(struct bfa_flash *flash,
+                           struct bfa_ioc *ioc, void *dev);
+void   bfa_nw_flash_memclaim(struct bfa_flash *flash, u8 *dm_kva, u64 dm_pa);
+
 #endif /* __BFA_IOC_H__ */
index 7a1393a..8230970 100644 (file)
@@ -83,6 +83,14 @@ union bfi_addr_u {
        } a32;
 };
 
+/**
+ * Generic DMA addr-len pair.
+ */
+struct bfi_alen {
+       union bfi_addr_u        al_addr;        /* DMA addr of buffer   */
+       u32                     al_len;         /* length of buffer */
+};
+
 /*
  * Large Message structure - 128 Bytes size Msgs
  */
@@ -476,6 +484,93 @@ struct bfi_msgq_i2h_cmdq_copy_req {
        u16     len;
 };
 
+/*
+ *      FLASH module specific
+ */
+enum bfi_flash_h2i_msgs {
+       BFI_FLASH_H2I_QUERY_REQ = 1,
+       BFI_FLASH_H2I_ERASE_REQ = 2,
+       BFI_FLASH_H2I_WRITE_REQ = 3,
+       BFI_FLASH_H2I_READ_REQ = 4,
+       BFI_FLASH_H2I_BOOT_VER_REQ = 5,
+};
+
+enum bfi_flash_i2h_msgs {
+       BFI_FLASH_I2H_QUERY_RSP = BFA_I2HM(1),
+       BFI_FLASH_I2H_ERASE_RSP = BFA_I2HM(2),
+       BFI_FLASH_I2H_WRITE_RSP = BFA_I2HM(3),
+       BFI_FLASH_I2H_READ_RSP = BFA_I2HM(4),
+       BFI_FLASH_I2H_BOOT_VER_RSP = BFA_I2HM(5),
+       BFI_FLASH_I2H_EVENT = BFA_I2HM(127),
+};
+
+/*
+ * Flash query request
+ */
+struct bfi_flash_query_req {
+       struct bfi_mhdr mh;   /* Common msg header */
+       struct bfi_alen alen;
+};
+
+/*
+ * Flash write request
+ */
+struct bfi_flash_write_req {
+       struct bfi_mhdr mh;     /* Common msg header */
+       struct bfi_alen alen;
+       u32     type;   /* partition type */
+       u8      instance; /* partition instance */
+       u8      last;
+       u8      rsv[2];
+       u32     offset;
+       u32     length;
+};
+
+/*
+ * Flash read request
+ */
+struct bfi_flash_read_req {
+       struct bfi_mhdr mh;     /* Common msg header */
+       u32     type;           /* partition type */
+       u8      instance;       /* partition instance */
+       u8      rsv[3];
+       u32     offset;
+       u32     length;
+       struct bfi_alen alen;
+};
+
+/*
+ * Flash query response
+ */
+struct bfi_flash_query_rsp {
+       struct bfi_mhdr mh;     /* Common msg header */
+       u32     status;
+};
+
+/*
+ * Flash read response
+ */
+struct bfi_flash_read_rsp {
+       struct bfi_mhdr mh;     /* Common msg header */
+       u32     type;           /* partition type */
+       u8      instance;       /* partition instance */
+       u8      rsv[3];
+       u32     status;
+       u32     length;
+};
+
+/*
+ * Flash write response
+ */
+struct bfi_flash_write_rsp {
+       struct bfi_mhdr mh;     /* Common msg header */
+       u32     type;           /* partition type */
+       u8      instance;       /* partition instance */
+       u8      rsv[3];
+       u32     status;
+       u32     length;
+};
+
 #pragma pack()
 
 #endif /* __BFI_H__ */
index 26f5c5a..bcfe296 100644 (file)
@@ -1740,6 +1740,11 @@ bna_ioceth_init(struct bna_ioceth *ioceth, struct bna *bna,
        kva += bfa_nw_cee_meminfo();
        dma += bfa_nw_cee_meminfo();
 
+       bfa_nw_flash_attach(&bna->flash, &ioceth->ioc, bna);
+       bfa_nw_flash_memclaim(&bna->flash, kva, dma);
+       kva += bfa_nw_flash_meminfo();
+       dma += bfa_nw_flash_meminfo();
+
        bfa_msgq_attach(&bna->msgq, &ioceth->ioc);
        bfa_msgq_memclaim(&bna->msgq, kva, dma);
        bfa_msgq_regisr(&bna->msgq, BFI_MC_ENET, bna_msgq_rsp_handler, bna);
@@ -1892,7 +1897,8 @@ bna_res_req(struct bna_res_info *res_info)
        res_info[BNA_RES_MEM_T_COM].res_u.mem_info.num = 1;
        res_info[BNA_RES_MEM_T_COM].res_u.mem_info.len = ALIGN(
                                (bfa_nw_cee_meminfo() +
-                               bfa_msgq_meminfo()), PAGE_SIZE);
+                                bfa_nw_flash_meminfo() +
+                                bfa_msgq_meminfo()), PAGE_SIZE);
 
        /* DMA memory for retrieving IOC attributes */
        res_info[BNA_RES_MEM_T_ATTR].res_type = BNA_RES_T_MEM;
index d090fbf..8e57fc5 100644 (file)
@@ -966,6 +966,7 @@ struct bna {
 
        struct bna_ioceth ioceth;
        struct bfa_cee cee;
+       struct bfa_flash flash;
        struct bfa_msgq msgq;
 
        struct bna_ethport ethport;
index 197af04..741f2e4 100644 (file)
@@ -48,7 +48,9 @@ MODULE_PARM_DESC(bnad_ioc_auto_recover, "Enable / Disable auto recovery");
  * Global variables
  */
 u32 bnad_rxqs_per_cq = 2;
-
+u32 bna_id;
+struct mutex bnad_list_mutex;
+LIST_HEAD(bnad_list);
 static const u8 bnad_bcast_addr[] =  {0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
 
 /*
@@ -75,6 +77,23 @@ do {                                                         \
 
 #define BNAD_TXRX_SYNC_MDELAY  250     /* 250 msecs */
 
+static void
+bnad_add_to_list(struct bnad *bnad)
+{
+       mutex_lock(&bnad_list_mutex);
+       list_add_tail(&bnad->list_entry, &bnad_list);
+       bnad->id = bna_id++;
+       mutex_unlock(&bnad_list_mutex);
+}
+
+static void
+bnad_remove_from_list(struct bnad *bnad)
+{
+       mutex_lock(&bnad_list_mutex);
+       list_del(&bnad->list_entry);
+       mutex_unlock(&bnad_list_mutex);
+}
+
 /*
  * Reinitialize completions in CQ, once Rx is taken down
  */
@@ -1084,6 +1103,16 @@ bnad_cb_enet_mtu_set(struct bnad *bnad)
        complete(&bnad->bnad_completions.mtu_comp);
 }
 
+void
+bnad_cb_completion(void *arg, enum bfa_status status)
+{
+       struct bnad_iocmd_comp *iocmd_comp =
+                       (struct bnad_iocmd_comp *)arg;
+
+       iocmd_comp->comp_status = (u32) status;
+       complete(&iocmd_comp->comp);
+}
+
 /* Resource allocation, free functions */
 
 static void
@@ -3167,12 +3196,14 @@ bnad_lock_init(struct bnad *bnad)
 {
        spin_lock_init(&bnad->bna_lock);
        mutex_init(&bnad->conf_mutex);
+       mutex_init(&bnad_list_mutex);
 }
 
 static void
 bnad_lock_uninit(struct bnad *bnad)
 {
        mutex_destroy(&bnad->conf_mutex);
+       mutex_destroy(&bnad_list_mutex);
 }
 
 /* PCI Initialization */
@@ -3253,8 +3284,8 @@ bnad_pci_probe(struct pci_dev *pdev,
                return err;
        }
        bnad = netdev_priv(netdev);
-
        bnad_lock_init(bnad);
+       bnad_add_to_list(bnad);
 
        mutex_lock(&bnad->conf_mutex);
        /*
@@ -3407,6 +3438,7 @@ pci_uninit:
        bnad_pci_uninit(pdev);
 unlock_mutex:
        mutex_unlock(&bnad->conf_mutex);
+       bnad_remove_from_list(bnad);
        bnad_lock_uninit(bnad);
        free_netdev(netdev);
        return err;
@@ -3445,6 +3477,7 @@ bnad_pci_remove(struct pci_dev *pdev)
        bnad_disable_msix(bnad);
        bnad_pci_uninit(pdev);
        mutex_unlock(&bnad->conf_mutex);
+       bnad_remove_from_list(bnad);
        bnad_lock_uninit(bnad);
        bnad_uninit(bnad);
        free_netdev(netdev);
index 5487ca4..459030c 100644 (file)
@@ -124,6 +124,12 @@ enum bnad_link_state {
        BNAD_LS_UP              = 1
 };
 
+struct bnad_iocmd_comp {
+       struct bnad             *bnad;
+       struct completion       comp;
+       int                     comp_status;
+};
+
 struct bnad_completion {
        struct completion       ioc_comp;
        struct completion       ucast_comp;
@@ -251,6 +257,8 @@ struct bnad_unmap_q {
 
 struct bnad {
        struct net_device       *netdev;
+       u32                     id;
+       struct list_head        list_entry;
 
        /* Data path */
        struct bnad_tx_info tx_info[BNAD_MAX_TX];
@@ -340,6 +348,7 @@ extern int bnad_mac_addr_set_locked(struct bnad *bnad, u8 *mac_addr);
 extern int bnad_enable_default_bcast(struct bnad *bnad);
 extern void bnad_restore_vlans(struct bnad *bnad, u32 rx_id);
 extern void bnad_set_ethtool_ops(struct net_device *netdev);
+extern void bnad_cb_completion(void *arg, enum bfa_status status);
 
 /* Configuration & setup */
 extern void bnad_tx_coalescing_timeo_set(struct bnad *bnad);
index 38d5c66..5f7be5a 100644 (file)
@@ -935,6 +935,143 @@ bnad_get_sset_count(struct net_device *netdev, int sset)
        }
 }
 
+static u32
+bnad_get_flash_partition_by_offset(struct bnad *bnad, u32 offset,
+                               u32 *base_offset)
+{
+       struct bfa_flash_attr *flash_attr;
+       struct bnad_iocmd_comp fcomp;
+       u32 i, flash_part = 0, ret;
+       unsigned long flags = 0;
+
+       flash_attr = kzalloc(sizeof(struct bfa_flash_attr), GFP_KERNEL);
+       if (!flash_attr)
+               return -ENOMEM;
+
+       fcomp.bnad = bnad;
+       fcomp.comp_status = 0;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       ret = bfa_nw_flash_get_attr(&bnad->bna.flash, flash_attr,
+                               bnad_cb_completion, &fcomp);
+       if (ret != BFA_STATUS_OK) {
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+               kfree(flash_attr);
+               goto out_err;
+       }
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       wait_for_completion(&fcomp.comp);
+       ret = fcomp.comp_status;
+
+       /* Check for the flash type & base offset value */
+       if (ret == BFA_STATUS_OK) {
+               for (i = 0; i < flash_attr->npart; i++) {
+                       if (offset >= flash_attr->part[i].part_off &&
+                           offset < (flash_attr->part[i].part_off +
+                                     flash_attr->part[i].part_size)) {
+                               flash_part = flash_attr->part[i].part_type;
+                               *base_offset = flash_attr->part[i].part_off;
+                               break;
+                       }
+               }
+       }
+       kfree(flash_attr);
+       return flash_part;
+out_err:
+       return -EINVAL;
+}
+
+static int
+bnad_get_eeprom_len(struct net_device *netdev)
+{
+       return BFA_TOTAL_FLASH_SIZE;
+}
+
+static int
+bnad_get_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
+               u8 *bytes)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       struct bnad_iocmd_comp fcomp;
+       u32 flash_part = 0, base_offset = 0;
+       unsigned long flags = 0;
+       int ret = 0;
+
+       /* Check if the flash read request is valid */
+       if (eeprom->magic != (bnad->pcidev->vendor |
+                            (bnad->pcidev->device << 16)))
+               return -EFAULT;
+
+       /* Query the flash partition based on the offset */
+       flash_part = bnad_get_flash_partition_by_offset(bnad,
+                               eeprom->offset, &base_offset);
+       if (flash_part <= 0)
+               return -EFAULT;
+
+       fcomp.bnad = bnad;
+       fcomp.comp_status = 0;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       ret = bfa_nw_flash_read_part(&bnad->bna.flash, flash_part,
+                               bnad->id, bytes, eeprom->len,
+                               eeprom->offset - base_offset,
+                               bnad_cb_completion, &fcomp);
+       if (ret != BFA_STATUS_OK) {
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+               goto done;
+       }
+
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       wait_for_completion(&fcomp.comp);
+       ret = fcomp.comp_status;
+done:
+       return ret;
+}
+
+static int
+bnad_set_eeprom(struct net_device *netdev, struct ethtool_eeprom *eeprom,
+               u8 *bytes)
+{
+       struct bnad *bnad = netdev_priv(netdev);
+       struct bnad_iocmd_comp fcomp;
+       u32 flash_part = 0, base_offset = 0;
+       unsigned long flags = 0;
+       int ret = 0;
+
+       /* Check if the flash update request is valid */
+       if (eeprom->magic != (bnad->pcidev->vendor |
+                            (bnad->pcidev->device << 16)))
+               return -EINVAL;
+
+       /* Query the flash partition based on the offset */
+       flash_part = bnad_get_flash_partition_by_offset(bnad,
+                               eeprom->offset, &base_offset);
+       if (flash_part <= 0)
+               return -EFAULT;
+
+       fcomp.bnad = bnad;
+       fcomp.comp_status = 0;
+
+       init_completion(&fcomp.comp);
+       spin_lock_irqsave(&bnad->bna_lock, flags);
+       ret = bfa_nw_flash_update_part(&bnad->bna.flash, flash_part,
+                               bnad->id, bytes, eeprom->len,
+                               eeprom->offset - base_offset,
+                               bnad_cb_completion, &fcomp);
+       if (ret != BFA_STATUS_OK) {
+               spin_unlock_irqrestore(&bnad->bna_lock, flags);
+               goto done;
+       }
+
+       spin_unlock_irqrestore(&bnad->bna_lock, flags);
+       wait_for_completion(&fcomp.comp);
+       ret = fcomp.comp_status;
+done:
+       return ret;
+}
+
 static struct ethtool_ops bnad_ethtool_ops = {
        .get_settings = bnad_get_settings,
        .set_settings = bnad_set_settings,
@@ -949,7 +1086,10 @@ static struct ethtool_ops bnad_ethtool_ops = {
        .set_pauseparam = bnad_set_pauseparam,
        .get_strings = bnad_get_strings,
        .get_ethtool_stats = bnad_get_ethtool_stats,
-       .get_sset_count = bnad_get_sset_count
+       .get_sset_count = bnad_get_sset_count,
+       .get_eeprom_len = bnad_get_eeprom_len,
+       .get_eeprom = bnad_get_eeprom,
+       .set_eeprom = bnad_set_eeprom,
 };
 
 void