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 @@ ...@@ -33,7 +33,7 @@
#define DRV_NAME "enic" #define DRV_NAME "enic"
#define DRV_DESCRIPTION "Cisco VIC Ethernet NIC Driver" #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 DRV_COPYRIGHT "Copyright 2008-2013 Cisco Systems, Inc"
#define ENIC_BARS_MAX 6 #define ENIC_BARS_MAX 6
...@@ -191,6 +191,25 @@ struct enic { ...@@ -191,6 +191,25 @@ struct enic {
struct vnic_gen_stats gen_stats; 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) static inline struct device *enic_get_dev(struct enic *enic)
{ {
return &(enic->pdev->dev); return &(enic->pdev->dev);
......
...@@ -2484,6 +2484,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent) ...@@ -2484,6 +2484,11 @@ static int enic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
goto err_out_iounmap; goto err_out_iounmap;
} }
err = vnic_devcmd_init(enic->vdev);
if (err)
goto err_out_vnic_unregister;
#ifdef CONFIG_PCI_IOV #ifdef CONFIG_PCI_IOV
/* Get number of subvnics */ /* Get number of subvnics */
pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV); pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
......
...@@ -24,6 +24,7 @@ ...@@ -24,6 +24,7 @@
#include "vnic_dev.h" #include "vnic_dev.h"
#include "vnic_cq.h" #include "vnic_cq.h"
#include "enic.h"
void vnic_cq_free(struct vnic_cq *cq) 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, ...@@ -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); cq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_CQ, index);
if (!cq->ctrl) { 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; return -EINVAL;
} }
......
...@@ -27,46 +27,9 @@ ...@@ -27,46 +27,9 @@
#include "vnic_resource.h" #include "vnic_resource.h"
#include "vnic_devcmd.h" #include "vnic_devcmd.h"
#include "vnic_dev.h" #include "vnic_dev.h"
#include "vnic_wq.h"
#include "vnic_stats.h" #include "vnic_stats.h"
#include "enic.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;
};
#define VNIC_MAX_RES_HDR_SIZE \ #define VNIC_MAX_RES_HDR_SIZE \
(sizeof(struct vnic_resource_header) + \ (sizeof(struct vnic_resource_header) + \
...@@ -90,14 +53,14 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, ...@@ -90,14 +53,14 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
return -EINVAL; return -EINVAL;
if (bar->len < VNIC_MAX_RES_HDR_SIZE) { 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; return -EINVAL;
} }
rh = bar->vaddr; rh = bar->vaddr;
mrh = bar->vaddr; mrh = bar->vaddr;
if (!rh) { if (!rh) {
pr_err("vNIC BAR0 res hdr not mem-mapped\n"); vdev_err("vNIC BAR0 res hdr not mem-mapped\n");
return -EINVAL; return -EINVAL;
} }
...@@ -106,11 +69,10 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, ...@@ -106,11 +69,10 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
(ioread32(&rh->version) != VNIC_RES_VERSION)) { (ioread32(&rh->version) != VNIC_RES_VERSION)) {
if ((ioread32(&mrh->magic) != MGMTVNIC_MAGIC) || if ((ioread32(&mrh->magic) != MGMTVNIC_MAGIC) ||
(ioread32(&mrh->version) != MGMTVNIC_VERSION)) { (ioread32(&mrh->version) != MGMTVNIC_VERSION)) {
pr_err("vNIC BAR0 res magic/version error " vdev_err("vNIC BAR0 res magic/version error exp (%lx/%lx) or (%lx/%lx), curr (%x/%x)\n",
"exp (%lx/%lx) or (%lx/%lx), curr (%x/%x)\n", VNIC_RES_MAGIC, VNIC_RES_VERSION,
VNIC_RES_MAGIC, VNIC_RES_VERSION, MGMTVNIC_MAGIC, MGMTVNIC_VERSION,
MGMTVNIC_MAGIC, MGMTVNIC_VERSION, ioread32(&rh->magic), ioread32(&rh->version));
ioread32(&rh->magic), ioread32(&rh->version));
return -EINVAL; return -EINVAL;
} }
} }
...@@ -144,17 +106,15 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev, ...@@ -144,17 +106,15 @@ static int vnic_dev_discover_res(struct vnic_dev *vdev,
/* each count is stride bytes long */ /* each count is stride bytes long */
len = count * VNIC_RES_STRIDE; len = count * VNIC_RES_STRIDE;
if (len + bar_offset > bar[bar_num].len) { if (len + bar_offset > bar[bar_num].len) {
pr_err("vNIC BAR0 resource %d " vdev_err("vNIC BAR0 resource %d out-of-bounds, offset 0x%x + size 0x%x > bar len 0x%lx\n",
"out-of-bounds, offset 0x%x + " type, bar_offset, len,
"size 0x%x > bar len 0x%lx\n", bar[bar_num].len);
type, bar_offset,
len,
bar[bar_num].len);
return -EINVAL; return -EINVAL;
} }
break; break;
case RES_TYPE_INTR_PBA_LEGACY: case RES_TYPE_INTR_PBA_LEGACY:
case RES_TYPE_DEVCMD: case RES_TYPE_DEVCMD:
case RES_TYPE_DEVCMD2:
len = count; len = count;
break; break;
default: default:
...@@ -238,8 +198,8 @@ int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring, ...@@ -238,8 +198,8 @@ int vnic_dev_alloc_desc_ring(struct vnic_dev *vdev, struct vnic_dev_ring *ring,
&ring->base_addr_unaligned); &ring->base_addr_unaligned);
if (!ring->descs_unaligned) { if (!ring->descs_unaligned) {
pr_err("Failed to allocate ring (size=%d), aborting\n", vdev_err("Failed to allocate ring (size=%d), aborting\n",
(int)ring->size); (int)ring->size);
return -ENOMEM; return -ENOMEM;
} }
...@@ -281,7 +241,7 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, ...@@ -281,7 +241,7 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
return -ENODEV; return -ENODEV;
} }
if (status & STAT_BUSY) { if (status & STAT_BUSY) {
pr_err("Busy devcmd %d\n", _CMD_N(cmd)); vdev_neterr("Busy devcmd %d\n", _CMD_N(cmd));
return -EBUSY; return -EBUSY;
} }
...@@ -315,8 +275,8 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, ...@@ -315,8 +275,8 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
return -err; return -err;
if (err != ERR_ECMDUNKNOWN || if (err != ERR_ECMDUNKNOWN ||
cmd != CMD_CAPABILITY) cmd != CMD_CAPABILITY)
pr_err("Error %d devcmd %d\n", vdev_neterr("Error %d devcmd %d\n",
err, _CMD_N(cmd)); err, _CMD_N(cmd));
return -err; return -err;
} }
...@@ -330,10 +290,160 @@ static int _vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd, ...@@ -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; 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, static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
enum vnic_devcmd_cmd proxy_cmd, enum vnic_devcmd_cmd cmd, enum vnic_devcmd_cmd proxy_cmd, enum vnic_devcmd_cmd cmd,
u64 *a0, u64 *a1, int wait) u64 *a0, u64 *a1, int wait)
...@@ -348,7 +458,7 @@ static int vnic_dev_cmd_proxy(struct vnic_dev *vdev, ...@@ -348,7 +458,7 @@ static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
vdev->args[2] = *a0; vdev->args[2] = *a0;
vdev->args[3] = *a1; vdev->args[3] = *a1;
err = _vnic_dev_cmd(vdev, proxy_cmd, wait); err = vdev->devcmd_rtn(vdev, proxy_cmd, wait);
if (err) if (err)
return err; return err;
...@@ -357,7 +467,8 @@ static int vnic_dev_cmd_proxy(struct vnic_dev *vdev, ...@@ -357,7 +467,8 @@ static int vnic_dev_cmd_proxy(struct vnic_dev *vdev,
err = (int)vdev->args[1]; err = (int)vdev->args[1];
if (err != ERR_ECMDUNKNOWN || if (err != ERR_ECMDUNKNOWN ||
cmd != CMD_CAPABILITY) 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; return err;
} }
...@@ -375,7 +486,7 @@ static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev, ...@@ -375,7 +486,7 @@ static int vnic_dev_cmd_no_proxy(struct vnic_dev *vdev,
vdev->args[0] = *a0; vdev->args[0] = *a0;
vdev->args[1] = *a1; vdev->args[1] = *a1;
err = _vnic_dev_cmd(vdev, cmd, wait); err = vdev->devcmd_rtn(vdev, cmd, wait);
*a0 = vdev->args[0]; *a0 = vdev->args[0];
*a1 = vdev->args[1]; *a1 = vdev->args[1];
...@@ -650,7 +761,7 @@ int vnic_dev_packet_filter(struct vnic_dev *vdev, int directed, int multicast, ...@@ -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); err = vnic_dev_cmd(vdev, CMD_PACKET_FILTER, &a0, &a1, wait);
if (err) if (err)
pr_err("Can't set packet filter\n"); vdev_neterr("Can't set packet filter\n");
return err; return err;
} }
...@@ -667,7 +778,7 @@ int vnic_dev_add_addr(struct vnic_dev *vdev, const u8 *addr) ...@@ -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); err = vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
if (err) 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; return err;
} }
...@@ -684,7 +795,7 @@ int vnic_dev_del_addr(struct vnic_dev *vdev, const u8 *addr) ...@@ -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); err = vnic_dev_cmd(vdev, CMD_ADDR_DEL, &a0, &a1, wait);
if (err) 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; return err;
} }
...@@ -728,7 +839,7 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr) ...@@ -728,7 +839,7 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
dma_addr_t notify_pa; dma_addr_t notify_pa;
if (vdev->notify || vdev->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; return -EINVAL;
} }
...@@ -838,7 +949,7 @@ int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev) ...@@ -838,7 +949,7 @@ int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev)
memset(vdev->args, 0, sizeof(vdev->args)); memset(vdev->args, 0, sizeof(vdev->args));
if (vnic_dev_capable(vdev, CMD_INTR_COAL_CONVERT)) 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 else
err = ERR_ECMDUNKNOWN; err = ERR_ECMDUNKNOWN;
...@@ -847,7 +958,7 @@ int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev) ...@@ -847,7 +958,7 @@ int vnic_dev_intr_coal_timer_info(struct vnic_dev *vdev)
*/ */
if ((err == ERR_ECMDUNKNOWN) || if ((err == ERR_ECMDUNKNOWN) ||
(!err && !(vdev->args[0] && vdev->args[1] && vdev->args[2]))) { (!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); vnic_dev_intr_coal_timer_info_default(vdev);
return 0; return 0;
} }
...@@ -938,6 +1049,9 @@ void vnic_dev_unregister(struct vnic_dev *vdev) ...@@ -938,6 +1049,9 @@ void vnic_dev_unregister(struct vnic_dev *vdev)
pci_free_consistent(vdev->pdev, pci_free_consistent(vdev->pdev,
sizeof(struct vnic_devcmd_fw_info), sizeof(struct vnic_devcmd_fw_info),
vdev->fw_info, vdev->fw_info_pa); vdev->fw_info, vdev->fw_info_pa);
if (vdev->devcmd2)
vnic_dev_deinit_devcmd2(vdev);
kfree(vdev); kfree(vdev);
} }
} }
...@@ -959,10 +1073,6 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev, ...@@ -959,10 +1073,6 @@ struct vnic_dev *vnic_dev_register(struct vnic_dev *vdev,
if (vnic_dev_discover_res(vdev, bar, num_bars)) if (vnic_dev_discover_res(vdev, bar, num_bars))
goto err_out; goto err_out;
vdev->devcmd = vnic_dev_get_res(vdev, RES_TYPE_DEVCMD, 0);
if (!vdev->devcmd)
goto err_out;
return vdev; return vdev;
err_out: err_out:
...@@ -977,6 +1087,29 @@ struct pci_dev *vnic_dev_get_pdev(struct vnic_dev *vdev) ...@@ -977,6 +1087,29 @@ struct pci_dev *vnic_dev_get_pdev(struct vnic_dev *vdev)
} }
EXPORT_SYMBOL(vnic_dev_get_pdev); 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) int vnic_dev_init_prov2(struct vnic_dev *vdev, u8 *buf, u32 len)
{ {
u64 a0, a1 = len; u64 a0, a1 = len;
......
...@@ -70,7 +70,48 @@ struct vnic_dev_ring { ...@@ -70,7 +70,48 @@ struct vnic_dev_ring {
unsigned int desc_avail; 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; struct vnic_stats;
void *vnic_dev_priv(struct vnic_dev *vdev); void *vnic_dev_priv(struct vnic_dev *vdev);
...@@ -135,5 +176,6 @@ int vnic_dev_deinit_done(struct vnic_dev *vdev, int *status); ...@@ -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_set_mac_addr(struct vnic_dev *vdev, u8 *mac_addr);
int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry, int vnic_dev_classifier(struct vnic_dev *vdev, u8 cmd, u16 *entry,
struct filter *data); struct filter *data);
int vnic_devcmd_init(struct vnic_dev *vdev);
#endif /* _VNIC_DEV_H_ */ #endif /* _VNIC_DEV_H_ */
...@@ -365,6 +365,12 @@ enum vnic_devcmd_cmd { ...@@ -365,6 +365,12 @@ enum vnic_devcmd_cmd {
*/ */
CMD_PROV_INFO_UPDATE = _CMDC(_CMD_DIR_WRITE, _CMD_VTYPE_ENET, 56), 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. /* Add a filter.
* in: (u64) a0= filter address * in: (u64) a0= filter address
* (u32) a1= size of filter * (u32) a1= size of filter
...@@ -629,4 +635,26 @@ struct vnic_devcmd { ...@@ -629,4 +635,26 @@ struct vnic_devcmd {
u64 args[VNIC_DEVCMD_NARGS]; /* RW cmd args (little-endian) */ 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_ */ #endif /* _VNIC_DEVCMD_H_ */
...@@ -25,6 +25,7 @@ ...@@ -25,6 +25,7 @@
#include "vnic_dev.h" #include "vnic_dev.h"
#include "vnic_intr.h" #include "vnic_intr.h"
#include "enic.h"
void vnic_intr_free(struct vnic_intr *intr) void vnic_intr_free(struct vnic_intr *intr)
{ {
...@@ -39,7 +40,7 @@ int vnic_intr_alloc(struct vnic_dev *vdev, 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); intr->ctrl = vnic_dev_get_res(vdev, RES_TYPE_INTR_CTRL, index);
if (!intr->ctrl) { 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; return -EINVAL;
} }
......
...@@ -48,6 +48,13 @@ enum vnic_res_type { ...@@ -48,6 +48,13 @@ enum vnic_res_type {
RES_TYPE_RSVD7, RES_TYPE_RSVD7,
RES_TYPE_DEVCMD, /* Device command region */ RES_TYPE_DEVCMD, /* Device command region */
RES_TYPE_PASS_THRU_PAGE, /* Pass-thru page */ 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 */ RES_TYPE_MAX, /* Count of resource types */
}; };
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "vnic_dev.h" #include "vnic_dev.h"
#include "vnic_rq.h" #include "vnic_rq.h"
#include "enic.h"
static int vnic_rq_alloc_bufs(struct vnic_rq *rq) 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, ...@@ -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); rq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_RQ, index);
if (!rq->ctrl) { 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; return -EINVAL;
} }
...@@ -167,6 +168,7 @@ void vnic_rq_enable(struct vnic_rq *rq) ...@@ -167,6 +168,7 @@ void vnic_rq_enable(struct vnic_rq *rq)
int vnic_rq_disable(struct vnic_rq *rq) int vnic_rq_disable(struct vnic_rq *rq)
{ {
unsigned int wait; unsigned int wait;
struct vnic_dev *vdev = rq->vdev;
iowrite32(0, &rq->ctrl->enable); iowrite32(0, &rq->ctrl->enable);
...@@ -177,7 +179,7 @@ int vnic_rq_disable(struct vnic_rq *rq) ...@@ -177,7 +179,7 @@ int vnic_rq_disable(struct vnic_rq *rq)
udelay(10); udelay(10);
} }
pr_err("Failed to disable RQ[%d]\n", rq->index); vdev_neterr("Failed to disable RQ[%d]\n", rq->index);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
......
...@@ -26,6 +26,7 @@ ...@@ -26,6 +26,7 @@
#include "vnic_dev.h" #include "vnic_dev.h"
#include "vnic_wq.h" #include "vnic_wq.h"
#include "enic.h"
static int vnic_wq_alloc_bufs(struct vnic_wq *wq) 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, ...@@ -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); wq->ctrl = vnic_dev_get_res(vdev, RES_TYPE_WQ, index);
if (!wq->ctrl) { 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; return -EINVAL;
} }
...@@ -113,10 +114,27 @@ int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index, ...@@ -113,10 +114,27 @@ int vnic_wq_alloc(struct vnic_dev *vdev, struct vnic_wq *wq, unsigned int index,
return 0; return 0;
} }
static void vnic_wq_init_start(struct vnic_wq *wq, unsigned int cq_index, int vnic_wq_devcmd2_alloc(struct vnic_dev *vdev, struct vnic_wq *wq,
unsigned int fetch_index, unsigned int posted_index, unsigned int desc_count, unsigned int desc_size)
unsigned int error_interrupt_enable, {
unsigned int error_interrupt_offset) 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; u64 paddr;
unsigned int count = wq->ring.desc_count; unsigned int count = wq->ring.desc_count;
...@@ -158,6 +176,7 @@ void vnic_wq_enable(struct vnic_wq *wq) ...@@ -158,6 +176,7 @@ void vnic_wq_enable(struct vnic_wq *wq)
int vnic_wq_disable(struct vnic_wq *wq) int vnic_wq_disable(struct vnic_wq *wq)
{ {
unsigned int wait; unsigned int wait;
struct vnic_dev *vdev = wq->vdev;
iowrite32(0, &wq->ctrl->enable); iowrite32(0, &wq->ctrl->enable);
...@@ -168,7 +187,7 @@ int vnic_wq_disable(struct vnic_wq *wq) ...@@ -168,7 +187,7 @@ int vnic_wq_disable(struct vnic_wq *wq)
udelay(10); udelay(10);
} }
pr_err("Failed to disable WQ[%d]\n", wq->index); vdev_neterr("Failed to disable WQ[%d]\n", wq->index);
return -ETIMEDOUT; return -ETIMEDOUT;
} }
......
...@@ -88,6 +88,17 @@ struct vnic_wq { ...@@ -88,6 +88,17 @@ struct vnic_wq {
unsigned int pkts_outstanding; 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) static inline unsigned int vnic_wq_desc_avail(struct vnic_wq *wq)
{ {
/* how many does SW own? */ /* how many does SW own? */
...@@ -174,5 +185,11 @@ void vnic_wq_enable(struct vnic_wq *wq); ...@@ -174,5 +185,11 @@ void vnic_wq_enable(struct vnic_wq *wq);
int vnic_wq_disable(struct vnic_wq *wq); int vnic_wq_disable(struct vnic_wq *wq);
void vnic_wq_clean(struct vnic_wq *wq, void vnic_wq_clean(struct vnic_wq *wq,
void (*buf_clean)(struct vnic_wq *wq, struct vnic_wq_buf *buf)); 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_ */ #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