bna: Added flash sub-module and ethtool eeprom entry points.

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>
This commit is contained in:
Krishna Gudipati 2011-12-22 13:29:45 +00:00 committed by David S. Miller
parent 6fc0d0f2e3
commit 72a9730b3f
9 changed files with 771 additions and 39 deletions

View 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__ */

View file

@ -2171,6 +2171,15 @@ bfa_nw_ioc_is_disabled(struct bfa_ioc *ioc)
bfa_fsm_cmp_state(ioc, bfa_ioc_sm_disabled);
}
/**
* 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;
}

View 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__ */

View 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__ */

View 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;

View 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;

View 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 @@ bnad_pci_probe(struct pci_dev *pdev,
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);

View 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);

View 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