Commit 863960b4 authored by David S. Miller's avatar David S. Miller

Merge branch 'enic-devcmd2'

Govindarajulu Varadarajan says:

====================
enic: add devcmd2

This series adds new devcmd2 support. The first two patches are code
refactoring.

devcmd is an interface for driver to communicate with fw/adaptor. It
involves writing data to hardware registers and waiting for the result.
This mechanism does not scale well. The queuing of "no wait" devcmds is
done in firmware memory rather than on the host. Firmware memory is a
rather more scarce and valuable resource than host memory. A devcmd storm
from one vf can disrupt the service on other pf/vf. The lack of flow
control allows for possible denial of server from one VM to another.
Devcmd2 uses work queue to post the devcmds, just like tx work queue. This
allows better flow control.
====================
Signed-off-by: default avatarDavid S. Miller <davem@davemloft.net>
parents 2ea273d7 373fb087
......@@ -33,7 +33,7 @@
#define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver"
#define DRV_VERSION "2.1.1.83"
#define DRV_VERSION "2.3.0.12"
#define DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc"
#define ENIC_BARS_MAX 6
......@@ -191,6 +191,25 @@ struct enic {
struct vnic_gen_stats gen_stats;
};
static inline struct net_device *vnic_get_netdev(struct vnic_dev *vdev)
{
struct enic *enic = vdev->priv;
return enic->netdev;
}
/* wrappers function for kernel log
* Make sure variable vdev of struct vnic_dev is available in the block where
* these macros are used
*/
#define vdev_info(args...) dev_info(&vdev->pdev->dev, args)
#define vdev_warn(args...) dev_warn(&vdev->pdev->dev, args)
#define vdev_err(args...) dev_err(&vdev->pdev->dev, args)
#define vdev_netinfo(args...) netdev_info(vnic_get_netdev(vdev), args)
#define vdev_netwarn(args...) netdev_warn(vnic_get_netdev(vdev), args)
#define vdev_neterr(args...) netdev_err(vnic_get_netdev(vdev), args)
static inline struct device *enic_get_dev(struct enic *enic)
{
return &(enic->pdev->dev);
......
......@@ -2484,6 +2484,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_iounmap;
}
err = vnic_devcmd_init(enic->vdev);
if (err)
goto err_out_vnic_unregister;
#ifdef CONFIG_PCI_IOV
/* Get number of subvnics */
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
......
......@@ -24,6 +24,7 @@
#include "vnic_dev.h"
#include "vnic_cq.h"
#include "enic.h"
void vnic_cq_free(struct vnic_cq *cq)
{
......@@ -42,7 +43,7 @@ int vnic_cq_alloc(struct vnic_dev *vdev, struct vnic_cq *cq, unsigned int index,
cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index);
if (!cq->ctrl) {
pr_err("Failed to hook CQ[%d] resource\n", index);
vdev_err("Failed to hook CQ[%d] resource\n", index);
return -EINVAL;
}
......
This diff is collapsed.
......@@ -70,7 +70,48 @@ struct vnic_dev_ring {
unsigned int desc_avail;
};
struct vnic_dev;
enum vnic_proxy_type {
PROXY_NONE,
PROXY_BY_BDF,
PROXY_BY_INDEX,
};
struct vnic_res {
void __iomem *vaddr;
dma_addr_t bus_addr;
unsigned int count;
};
struct vnic_intr_coal_timer_info {
u32 mul;
u32 div;
u32 max_usec;
};
struct vnic_dev {
void *priv;
struct pci_dev *pdev;
struct vnic_res res[RES_TYPE_MAX];
enum vnic_dev_intr_mode intr_mode;
struct vnic_devcmd __iomem *devcmd;
struct vnic_devcmd_notify *notify;
struct vnic_devcmd_notify notify_copy;
dma_addr_t notify_pa;
u32 notify_sz;
dma_addr_t linkstatus_pa;
struct vnic_stats *stats;
dma_addr_t stats_pa;
struct vnic_devcmd_fw_info *fw_info;
dma_addr_t fw_info_pa;
enum vnic_proxy_type proxy;
u32 proxy_index;
u64 args[VNIC_DEVCMD_NARGS];
struct vnic_intr_coal_timer_info intr_coal_timer_info;
struct devcmd2_controller *devcmd2;
int (*devcmd_rtn)(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
int wait);
};
struct vnic_stats;
void *vnic_dev_priv(struct vnic_dev *vdev);
......@@ -135,5 +176,6 @@ int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status);
int vnic_dev_set_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
struct filter *data);
int vnic_devcmd_init(struct vnic_dev *vdev);
#endif /* _VNIC_DEV_H_ */
......@@ -365,6 +365,12 @@ enum vnic_devcmd_cmd {
*/
CMD_PROV_INFO_UPDATE = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 56),
/* Initialization for the devcmd2 interface.
* in: (u64) a0 = host result buffer physical address
* in: (u16) a1 = number of entries in result buffer
*/
CMD_INITIALIZE_DEVCMD2 = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 57),
/* Add a filter.
* in: (u64) a0= filter address
* (u32) a1= size of filter
......@@ -629,4 +635,26 @@ struct vnic_devcmd {
u64 args[VNIC_DEVCMD_NARGS]; /* RW cmd args (little-endian) */
};
#define DEVCMD2_FNORESULT 0x1 /* Don't copy result to host */
#define VNIC_DEVCMD2_NARGS VNIC_DEVCMD_NARGS
struct vnic_devcmd2 {
u16 pad;
u16 flags;
u32 cmd;
u64 args[VNIC_DEVCMD2_NARGS];
};
#define VNIC_DEVCMD2_NRESULTS VNIC_DEVCMD_NARGS
struct devcmd2_result {
u64 results[VNIC_DEVCMD2_NRESULTS];
u32 pad;
u16 completed_index;
u8 error;
u8 color;
};
#define DEVCMD2_RING_SIZE 32
#define DEVCMD2_DESC_SIZE 128
#endif /* _VNIC_DEVCMD_H_ */
......@@ -25,6 +25,7 @@
#include "vnic_dev.h"
#include "vnic_intr.h"
#include "enic.h"
void vnic_intr_free(struct vnic_intr *intr)
{
......@@ -39,7 +40,7 @@ int vnic_intr_alloc(struct vnic_dev *vdev, struct vnic_intr *intr,
intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index);
if (!intr->ctrl) {
pr_err("Failed to hook INTR[%d].ctrl resource\n", index);
vdev_err("Failed to hook INTR[%d].ctrl resource\n", index);
return -EINVAL;
}
......
......@@ -48,6 +48,13 @@ enum vnic_res_type {
RES_TYPE_RSVD7,
RES_TYPE_DEVCMD, /* Device command region */
RES_TYPE_PASS_THRU_PAGE, /* Pass-thru page */
RES_TYPE_SUBVNIC, /* subvnic resource type */
RES_TYPE_MQ_WQ, /* MQ Work queues */
RES_TYPE_MQ_RQ, /* MQ Receive queues */
RES_TYPE_MQ_CQ, /* MQ Completion queues */
RES_TYPE_DEPRECATED1, /* Old version of devcmd 2 */
RES_TYPE_DEPRECATED2, /* Old version of devcmd 2 */
RES_TYPE_DEVCMD2, /* Device control region */
RES_TYPE_MAX, /* Count of resource types */
};
......
......@@ -26,6 +26,7 @@
#include "vnic_dev.h"
#include "vnic_rq.h"
#include "enic.h"
static int vnic_rq_alloc_bufs(struct vnic_rq *rq)
{
......@@ -91,7 +92,7 @@ int vnic_rq_alloc(struct vnic_dev *vdev, struct vnic_rq *rq, unsigned int index,
rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index);
if (!rq->ctrl) {
pr_err("Failed to hook RQ[%d] resource\n", index);
vdev_err("Failed to hook RQ[%d] resource\n", index);
return -EINVAL;
}
......@@ -167,6 +168,7 @@ void vnic_rq_enable(struct vnic_rq *rq)
int vnic_rq_disable(struct vnic_rq *rq)
{
unsigned int wait;
struct vnic_dev *vdev = rq->vdev;
iowrite32(0, &rq->ctrl->enable);
......@@ -177,7 +179,7 @@ int vnic_rq_disable(struct vnic_rq *rq)
udelay(10);
}
pr_err("Failed to disable RQ[%d]\n", rq->index);
vdev_neterr("Failed to disable RQ[%d]\n", rq->index);
return -ETIMEDOUT;
}
......
......@@ -26,6 +26,7 @@
#include "vnic_dev.h"
#include "vnic_wq.h"
#include "enic.h"
static int vnic_wq_alloc_bufs(struct vnic_wq *wq)
{
......@@ -94,7 +95,7 @@ int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index);
if (!wq->ctrl) {
pr_err("Failed to hook WQ[%d] resource\n", index);
vdev_err("Failed to hook WQ[%d] resource\n", index);
return -EINVAL;
}
......@@ -113,10 +114,27 @@ int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
return 0;
}
static void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
unsigned int fetch_index, unsigned int posted_index,
unsigned int error_interrupt_enable,
unsigned int error_interrupt_offset)
int vnic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq,
unsigned int desc_count, unsigned int desc_size)
{
int err;
wq->index = 0;
wq->vdev = vdev;
wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD2, 0);
if (!wq->ctrl)
return -EINVAL;
vnic_wq_disable(wq);
err = vnic_dev_alloc_desc_ring(vdev, &wq->ring, desc_count, desc_size);
return err;
}
void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
unsigned int fetch_index, unsigned int posted_index,
unsigned int error_interrupt_enable,
unsigned int error_interrupt_offset)
{
u64 paddr;
unsigned int count = wq->ring.desc_count;
......@@ -158,6 +176,7 @@ void vnic_wq_enable(struct vnic_wq *wq)
int vnic_wq_disable(struct vnic_wq *wq)
{
unsigned int wait;
struct vnic_dev *vdev = wq->vdev;
iowrite32(0, &wq->ctrl->enable);
......@@ -168,7 +187,7 @@ int vnic_wq_disable(struct vnic_wq *wq)
udelay(10);
}
pr_err("Failed to disable WQ[%d]\n", wq->index);
vdev_neterr("Failed to disable WQ[%d]\n", wq->index);
return -ETIMEDOUT;
}
......
......@@ -88,6 +88,17 @@ struct vnic_wq {
unsigned int pkts_outstanding;
};
struct devcmd2_controller {
struct vnic_wq_ctrl __iomem *wq_ctrl;
struct vnic_devcmd2 *cmd_ring;
struct devcmd2_result *result;
u16 next_result;
u16 result_size;
int color;
struct vnic_dev_ring results_ring;
struct vnic_wq wq;
};
static inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq)
{
/* how many does SW own? */
......@@ -174,5 +185,11 @@ void vnic_wq_enable(struct vnic_wq *wq);
int vnic_wq_disable(struct vnic_wq *wq);
void vnic_wq_clean(struct vnic_wq *wq,
void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf));
int vnic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq,
unsigned int desc_count, unsigned int desc_size);
void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index,
unsigned int fetch_index, unsigned int posted_index,
unsigned int error_interrupt_enable,
unsigned int error_interrupt_offset);
#endif /* _VNIC_WQ_H_ */
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment