mirror of
https://github.com/torvalds/linux
synced 2024-11-05 18:23:50 +00:00
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: David S. Miller <davem@davemloft.net>
This commit is contained in:
commit
863960b4c5
11 changed files with 357 additions and 83 deletions
|
@ -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;
|
||||
}
|
||||
|
||||
|
|
|
@ -27,46 +27,9 @@
|
|||
#include "vnic_resource.h"
|
||||
#include "vnic_devcmd.h"
|
||||
#include "vnic_dev.h"
|
||||
#include "vnic_wq.h"
|
||||
#include "vnic_stats.h"
|
||||
|
||||
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;
|
||||
};
|
||||
#include "enic.h"
|
||||
|
||||
#define VNIC_MAX_RES_HDR_SIZE \
|
||||
(sizeof(struct vnic_resource_header) + \
|
||||
|
@ -90,14 +53,14 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
|
|||
return -EINVAL;
|
||||
|
||||
if (bar->len < VNIC_MAX_RES_HDR_SIZE) {
|
||||
pr_err("vNIC BAR0 res hdr length error\n");
|
||||
vdev_err("vNIC BAR0 res hdr length error\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
rh = bar->vaddr;
|
||||
mrh = bar->vaddr;
|
||||
if (!rh) {
|
||||
pr_err("vNIC BAR0 res hdr not mem-mapped\n");
|
||||
vdev_err("vNIC BAR0 res hdr not mem-mapped\n");
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -106,11 +69,10 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
|
|||
(ioread32(&rh->version) != VNIC_RES_VERSION)) {
|
||||
if ((ioread32(&mrh->magic) != MGMTVNIC_MAGIC) ||
|
||||
(ioread32(&mrh->version) != MGMTVNIC_VERSION)) {
|
||||
pr_err("vNIC BAR0 res magic/version error "
|
||||
"exp (%lx/%lx) or (%lx/%lx), curr (%x/%x)\n",
|
||||
VNIC_RES_MAGIC, VNIC_RES_VERSION,
|
||||
MGMTVNIC_MAGIC, MGMTVNIC_VERSION,
|
||||
ioread32(&rh->magic), ioread32(&rh->version));
|
||||
vdev_err("vNIC BAR0 res magic/version error exp (%lx/%lx) or (%lx/%lx), curr (%x/%x)\n",
|
||||
VNIC_RES_MAGIC, VNIC_RES_VERSION,
|
||||
MGMTVNIC_MAGIC, MGMTVNIC_VERSION,
|
||||
ioread32(&rh->magic), ioread32(&rh->version));
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
@ -144,17 +106,15 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
|
|||
/* each count is stride bytes long */
|
||||
len = count * VNIC_RES_STRIDE;
|
||||
if (len + bar_offset > bar[bar_num].len) {
|
||||
pr_err("vNIC BAR0 resource %d "
|
||||
"out-of-bounds, offset 0x%x + "
|
||||
"size 0x%x > bar len 0x%lx\n",
|
||||
type, bar_offset,
|
||||
len,
|
||||
bar[bar_num].len);
|
||||
vdev_err("vNIC BAR0 resource %d out-of-bounds, offset 0x%x + size 0x%x > bar len 0x%lx\n",
|
||||
type, bar_offset, len,
|
||||
bar[bar_num].len);
|
||||
return -EINVAL;
|
||||
}
|
||||
break;
|
||||
case RES_TYPE_INTR_PBA_LEGACY:
|
||||
case RES_TYPE_DEVCMD:
|
||||
case RES_TYPE_DEVCMD2:
|
||||
len = count;
|
||||
break;
|
||||
default:
|
||||
|
@ -238,8 +198,8 @@ int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
|
|||
&ring->base_addr_unaligned);
|
||||
|
||||
if (!ring->descs_unaligned) {
|
||||
pr_err("Failed to allocate ring (size=%d), aborting\n",
|
||||
(int)ring->size);
|
||||
vdev_err("Failed to allocate ring (size=%d), aborting\n",
|
||||
(int)ring->size);
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
|
@ -281,7 +241,7 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
|
|||
return -ENODEV;
|
||||
}
|
||||
if (status & STAT_BUSY) {
|
||||
pr_err("Busy devcmd %d\n", _CMD_N(cmd));
|
||||
vdev_neterr("Busy devcmd %d\n", _CMD_N(cmd));
|
||||
return -EBUSY;
|
||||
}
|
||||
|
||||
|
@ -315,8 +275,8 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
|
|||
return -err;
|
||||
if (err != ERR_ECMDUNKNOWN ||
|
||||
cmd != CMD_CAPABILITY)
|
||||
pr_err("Error %d devcmd %d\n",
|
||||
err, _CMD_N(cmd));
|
||||
vdev_neterr("Error %d devcmd %d\n",
|
||||
err, _CMD_N(cmd));
|
||||
return -err;
|
||||
}
|
||||
|
||||
|
@ -330,10 +290,160 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
|
|||
}
|
||||
}
|
||||
|
||||
pr_err("Timedout devcmd %d\n", _CMD_N(cmd));
|
||||
vdev_neterr("Timedout devcmd %d\n", _CMD_N(cmd));
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int _vnic_dev_cmd2(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
|
||||
int wait)
|
||||
{
|
||||
struct devcmd2_controller *dc2c = vdev->devcmd2;
|
||||
struct devcmd2_result *result = dc2c->result + dc2c->next_result;
|
||||
unsigned int i;
|
||||
int delay, err;
|
||||
u32 fetch_index, posted, new_posted;
|
||||
|
||||
posted = ioread32(&dc2c->wq_ctrl->posted_index);
|
||||
fetch_index = ioread32(&dc2c->wq_ctrl->fetch_index);
|
||||
|
||||
if (posted == 0xFFFFFFFF || fetch_index == 0xFFFFFFFF)
|
||||
return -ENODEV;
|
||||
|
||||
new_posted = (posted + 1) % DEVCMD2_RING_SIZE;
|
||||
|
||||
if (new_posted == fetch_index) {
|
||||
vdev_neterr("devcmd2 %d: wq is full. fetch index: %u, posted index: %u\n",
|
||||
_CMD_N(cmd), fetch_index, posted);
|
||||
return -EBUSY;
|
||||
}
|
||||
dc2c->cmd_ring[posted].cmd = cmd;
|
||||
dc2c->cmd_ring[posted].flags = 0;
|
||||
|
||||
if ((_CMD_FLAGS(cmd) & _CMD_FLAGS_NOWAIT))
|
||||
dc2c->cmd_ring[posted].flags |= DEVCMD2_FNORESULT;
|
||||
if (_CMD_DIR(cmd) & _CMD_DIR_WRITE)
|
||||
for (i = 0; i < VNIC_DEVCMD_NARGS; i++)
|
||||
dc2c->cmd_ring[posted].args[i] = vdev->args[i];
|
||||
|
||||
/* Adding write memory barrier prevents compiler and/or CPU reordering,
|
||||
* thus avoiding descriptor posting before descriptor is initialized.
|
||||
* Otherwise, hardware can read stale descriptor fields.
|
||||
*/
|
||||
wmb();
|
||||
iowrite32(new_posted, &dc2c->wq_ctrl->posted_index);
|
||||
|
||||
if (dc2c->cmd_ring[posted].flags & DEVCMD2_FNORESULT)
|
||||
return 0;
|
||||
|
||||
for (delay = 0; delay < wait; delay++) {
|
||||
if (result->color == dc2c->color) {
|
||||
dc2c->next_result++;
|
||||
if (dc2c->next_result == dc2c->result_size) {
|
||||
dc2c->next_result = 0;
|
||||
dc2c->color = dc2c->color ? 0 : 1;
|
||||
}
|
||||
if (result->error) {
|
||||
err = result->error;
|
||||
if (err != ERR_ECMDUNKNOWN ||
|
||||
cmd != CMD_CAPABILITY)
|
||||
vdev_neterr("Error %d devcmd %d\n",
|
||||
err, _CMD_N(cmd));
|
||||
return -err;
|
||||
}
|
||||
if (_CMD_DIR(cmd) & _CMD_DIR_READ)
|
||||
for (i = 0; i < VNIC_DEVCMD2_NARGS; i++)
|
||||
vdev->args[i] = result->results[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
udelay(100);
|
||||
}
|
||||
|
||||
vdev_neterr("devcmd %d timed out\n", _CMD_N(cmd));
|
||||
|
||||
return -ETIMEDOUT;
|
||||
}
|
||||
|
||||
static int vnic_dev_init_devcmd1(struct vnic_dev *vdev)
|
||||
{
|
||||
vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0);
|
||||
if (!vdev->devcmd)
|
||||
return -ENODEV;
|
||||
vdev->devcmd_rtn = _vnic_dev_cmd;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int vnic_dev_init_devcmd2(struct vnic_dev *vdev)
|
||||
{
|
||||
int err;
|
||||
unsigned int fetch_index;
|
||||
|
||||
if (vdev->devcmd2)
|
||||
return 0;
|
||||
|
||||
vdev->devcmd2 = kzalloc(sizeof(*vdev->devcmd2), GFP_KERNEL);
|
||||
if (!vdev->devcmd2)
|
||||
return -ENOMEM;
|
||||
|
||||
vdev->devcmd2->color = 1;
|
||||
vdev->devcmd2->result_size = DEVCMD2_RING_SIZE;
|
||||
err = vnic_wq_devcmd2_alloc(vdev, &vdev->devcmd2->wq, DEVCMD2_RING_SIZE,
|
||||
DEVCMD2_DESC_SIZE);
|
||||
if (err)
|
||||
goto err_free_devcmd2;
|
||||
|
||||
fetch_index = ioread32(&vdev->devcmd2->wq.ctrl->fetch_index);
|
||||
if (fetch_index == 0xFFFFFFFF) { /* check for hardware gone */
|
||||
vdev_err("Fatal error in devcmd2 init - hardware surprise removal");
|
||||
|
||||
return -ENODEV;
|
||||
}
|
||||
|
||||
vnic_wq_init_start(&vdev->devcmd2->wq, 0, fetch_index, fetch_index, 0,
|
||||
0);
|
||||
vnic_wq_enable(&vdev->devcmd2->wq);
|
||||
|
||||
err = vnic_dev_alloc_desc_ring(vdev, &vdev->devcmd2->results_ring,
|
||||
DEVCMD2_RING_SIZE, DEVCMD2_DESC_SIZE);
|
||||
if (err)
|
||||
goto err_free_wq;
|
||||
|
||||
vdev->devcmd2->result = vdev->devcmd2->results_ring.descs;
|
||||
vdev->devcmd2->cmd_ring = vdev->devcmd2->wq.ring.descs;
|
||||
vdev->devcmd2->wq_ctrl = vdev->devcmd2->wq.ctrl;
|
||||
vdev->args[0] = (u64)vdev->devcmd2->results_ring.base_addr |
|
||||
VNIC_PADDR_TARGET;
|
||||
vdev->args[1] = DEVCMD2_RING_SIZE;
|
||||
|
||||
err = _vnic_dev_cmd2(vdev, CMD_INITIALIZE_DEVCMD2, 1000);
|
||||
if (err)
|
||||
goto err_free_desc_ring;
|
||||
|
||||
vdev->devcmd_rtn = _vnic_dev_cmd2;
|
||||
|
||||
return 0;
|
||||
|
||||
err_free_desc_ring:
|
||||
vnic_dev_free_desc_ring(vdev, &vdev->devcmd2->results_ring);
|
||||
err_free_wq:
|
||||
vnic_wq_disable(&vdev->devcmd2->wq);
|
||||
vnic_wq_free(&vdev->devcmd2->wq);
|
||||
err_free_devcmd2:
|
||||
kfree(vdev->devcmd2);
|
||||
vdev->devcmd2 = NULL;
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
static void vnic_dev_deinit_devcmd2(struct vnic_dev *vdev)
|
||||
{
|
||||
vnic_dev_free_desc_ring(vdev, &vdev->devcmd2->results_ring);
|
||||
vnic_wq_disable(&vdev->devcmd2->wq);
|
||||
vnic_wq_free(&vdev->devcmd2->wq);
|
||||
kfree(vdev->devcmd2);
|
||||
}
|
||||
|
||||
static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
|
||||
enum vnic_devcmd_cmd proxy_cmd, enum vnic_devcmd_cmd cmd,
|
||||
u64 *a0, u64 *a1, int wait)
|
||||
|
@ -348,7 +458,7 @@ static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
|
|||
vdev->args[2] = *a0;
|
||||
vdev->args[3] = *a1;
|
||||
|
||||
err = _vnic_dev_cmd(vdev, proxy_cmd, wait);
|
||||
err = vdev->devcmd_rtn(vdev, proxy_cmd, wait);
|
||||
if (err)
|
||||
return err;
|
||||
|
||||
|
@ -357,7 +467,8 @@ static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
|
|||
err = (int)vdev->args[1];
|
||||
if (err != ERR_ECMDUNKNOWN ||
|
||||
cmd != CMD_CAPABILITY)
|
||||
pr_err("Error %d proxy devcmd %d\n", err, _CMD_N(cmd));
|
||||
vdev_neterr("Error %d proxy devcmd %d\n", err,
|
||||
_CMD_N(cmd));
|
||||
return err;
|
||||
}
|
||||
|
||||
|
@ -375,7 +486,7 @@ static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev,
|
|||
vdev->args[0] = *a0;
|
||||
vdev->args[1] = *a1;
|
||||
|
||||
err = _vnic_dev_cmd(vdev, cmd, wait);
|
||||
err = vdev->devcmd_rtn(vdev, cmd, wait);
|
||||
|
||||
*a0 = vdev->args[0];
|
||||
*a1 = vdev->args[1];
|
||||
|
@ -650,7 +761,7 @@ int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast,
|
|||
|
||||
err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait);
|
||||
if (err)
|
||||
pr_err("Can't set packet filter\n");
|
||||
vdev_neterr("Can't set packet filter\n");
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -667,7 +778,7 @@ int vnic_dev_add_addr(struct vnic_dev *vdev, const u8 *addr)
|
|||
|
||||
err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
|
||||
if (err)
|
||||
pr_err("Can't add addr [%pM], %d\n", addr, err);
|
||||
vdev_neterr("Can't add addr [%pM], %d\n", addr, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -684,7 +795,7 @@ int vnic_dev_del_addr(struct vnic_dev *vdev, const u8 *addr)
|
|||
|
||||
err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
|
||||
if (err)
|
||||
pr_err("Can't del addr [%pM], %d\n", addr, err);
|
||||
vdev_neterr("Can't del addr [%pM], %d\n", addr, err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
@ -728,7 +839,7 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
|
|||
dma_addr_t notify_pa;
|
||||
|
||||
if (vdev->notify || vdev->notify_pa) {
|
||||
pr_err("notify block %p still allocated", vdev->notify);
|
||||
vdev_neterr("notify block %p still allocated", vdev->notify);
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
|
@ -838,7 +949,7 @@ int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev)
|
|||
memset(vdev->args, 0, sizeof(vdev->args));
|
||||
|
||||
if (vnic_dev_capable(vdev, CMD_INTR_COAL_CONVERT))
|
||||
err = _vnic_dev_cmd(vdev, CMD_INTR_COAL_CONVERT, wait);
|
||||
err = vdev->devcmd_rtn(vdev, CMD_INTR_COAL_CONVERT, wait);
|
||||
else
|
||||
err = ERR_ECMDUNKNOWN;
|
||||
|
||||
|
@ -847,7 +958,7 @@ int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev)
|
|||
*/
|
||||
if ((err == ERR_ECMDUNKNOWN) ||
|
||||
(!err && !(vdev->args[0] && vdev->args[1] && vdev->args[2]))) {
|
||||
pr_warn("Using default conversion factor for interrupt coalesce timer\n");
|
||||
vdev_netwarn("Using default conversion factor for interrupt coalesce timer\n");
|
||||
vnic_dev_intr_coal_timer_info_default(vdev);
|
||||
return 0;
|
||||
}
|
||||
|
@ -938,6 +1049,9 @@ void vnic_dev_unregister(struct vnic_dev *vdev)
|
|||
pci_free_consistent(vdev->pdev,
|
||||
sizeof(struct vnic_devcmd_fw_info),
|
||||
vdev->fw_info, vdev->fw_info_pa);
|
||||
if (vdev->devcmd2)
|
||||
vnic_dev_deinit_devcmd2(vdev);
|
||||
|
||||
kfree(vdev);
|
||||
}
|
||||
}
|
||||
|
@ -959,10 +1073,6 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
|
|||
if (vnic_dev_discover_res(vdev, bar, num_bars))
|
||||
goto err_out;
|
||||
|
||||
vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0);
|
||||
if (!vdev->devcmd)
|
||||
goto err_out;
|
||||
|
||||
return vdev;
|
||||
|
||||
err_out:
|
||||
|
@ -977,6 +1087,29 @@ struct pci_dev *vnic_dev_get_pdev(struct vnic_dev *vdev)
|
|||
}
|
||||
EXPORT_SYMBOL(vnic_dev_get_pdev);
|
||||
|
||||
int vnic_devcmd_init(struct vnic_dev *vdev)
|
||||
{
|
||||
int err;
|
||||
void *res;
|
||||
|
||||
res = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD2, 0);
|
||||
if (res) {
|
||||
err = vnic_dev_init_devcmd2(vdev);
|
||||
if (err)
|
||||
vdev_warn("DEVCMD2 init failed: %d, Using DEVCMD1",
|
||||
err);
|
||||
else
|
||||
return 0;
|
||||
} else {
|
||||
vdev_warn("DEVCMD2 resource not found (old firmware?) Using DEVCMD1\n");
|
||||
}
|
||||
err = vnic_dev_init_devcmd1(vdev);
|
||||
if (err)
|
||||
vdev_err("DEVCMD1 initialization failed: %d", err);
|
||||
|
||||
return err;
|
||||
}
|
||||
|
||||
int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len)
|
||||
{
|
||||
u64 a0, a1 = len;
|
||||
|
|
|
@ -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_ */
|
||||
|
|
Loading…
Reference in a new issue