summaryrefslogtreecommitdiffstats
path: root/drivers/net/enic/vnic_dev.c
diff options
context:
space:
mode:
authorScott Feldman <scofeldm@cisco.com>2008-11-21 21:28:18 -0800
committerDavid S. Miller <davem@davemloft.net>2008-11-21 21:28:18 -0800
commit27372bf5fa5ffc0fee3ddb486a0da942295fd8e0 (patch)
tree34a4e6f41057ff12f01a86d891c81023c3d45a8e /drivers/net/enic/vnic_dev.c
parent86ca9db794a285f18f31ed15601696b238ccb57a (diff)
downloadtalos-obmc-linux-27372bf5fa5ffc0fee3ddb486a0da942295fd8e0.tar.gz
talos-obmc-linux-27372bf5fa5ffc0fee3ddb486a0da942295fd8e0.zip
enic: driver/firmware API updates
Add driver/firmware compatibility check. Update firmware notify cmd to honor notify area size. Add new version of init cmd. Add link_down_cnt to notify area to track link down count. Signed-off-by: Scott Feldman <scofeldm@cisco.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/enic/vnic_dev.c')
-rw-r--r--drivers/net/enic/vnic_dev.c60
1 files changed, 42 insertions, 18 deletions
diff --git a/drivers/net/enic/vnic_dev.c b/drivers/net/enic/vnic_dev.c
index 9afd33c7188d..08a37b01bf37 100644
--- a/drivers/net/enic/vnic_dev.c
+++ b/drivers/net/enic/vnic_dev.c
@@ -43,6 +43,7 @@ struct vnic_dev {
struct vnic_devcmd_notify *notify;
struct vnic_devcmd_notify notify_copy;
dma_addr_t notify_pa;
+ u32 notify_sz;
u32 *linkstatus;
dma_addr_t linkstatus_pa;
struct vnic_stats *stats;
@@ -235,14 +236,6 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
struct vnic_devcmd __iomem *devcmd = vdev->devcmd;
int delay;
u32 status;
- int dev_cmd_err[] = {
- /* convert from fw's version of error.h to host's version */
- 0, /* ERR_SUCCESS */
- EINVAL, /* ERR_EINVAL */
- EFAULT, /* ERR_EFAULT */
- EPERM, /* ERR_EPERM */
- EBUSY, /* ERR_EBUSY */
- };
int err;
status = ioread32(&devcmd->status);
@@ -270,10 +263,12 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
if (!(status & STAT_BUSY)) {
if (status & STAT_ERROR) {
- err = dev_cmd_err[(int)readq(&devcmd->args[0])];
- printk(KERN_ERR "Error %d devcmd %d\n",
- err, _CMD_N(cmd));
- return -err;
+ err = (int)readq(&devcmd->args[0]);
+ if (err != ERR_ECMDUNKNOWN ||
+ cmd != CMD_CAPABILITY)
+ printk(KERN_ERR "Error %d devcmd %d\n",
+ err, _CMD_N(cmd));
+ return err;
}
if (_CMD_DIR(cmd) & _CMD_DIR_READ) {
@@ -290,6 +285,17 @@ int vnic_dev_cmd(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd,
return -ETIMEDOUT;
}
+int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd)
+{
+ u64 a0 = (u32)cmd, a1 = 0;
+ int wait = 1000;
+ int err;
+
+ err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait);
+
+ return !(err || a0);
+}
+
int vnic_dev_fw_info(struct vnic_dev *vdev,
struct vnic_devcmd_fw_info **fw_info)
{
@@ -511,6 +517,7 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
{
u64 a0, a1;
int wait = 1000;
+ int r;
if (!vdev->notify) {
vdev->notify = pci_alloc_consistent(vdev->pdev,
@@ -518,13 +525,16 @@ int vnic_dev_notify_set(struct vnic_dev *vdev, u16 intr)
&vdev->notify_pa);
if (!vdev->notify)
return -ENOMEM;
+ memset(vdev->notify, 0, sizeof(struct vnic_devcmd_notify));
}
a0 = vdev->notify_pa;
a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL;
a1 += sizeof(struct vnic_devcmd_notify);
- return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+ r = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+ vdev->notify_sz = (r == 0) ? (u32)a1 : 0;
+ return r;
}
void vnic_dev_notify_unset(struct vnic_dev *vdev)
@@ -537,22 +547,22 @@ void vnic_dev_notify_unset(struct vnic_dev *vdev)
a1 += sizeof(struct vnic_devcmd_notify);
vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait);
+ vdev->notify_sz = 0;
}
static int vnic_dev_notify_ready(struct vnic_dev *vdev)
{
u32 *words;
- unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4;
+ unsigned int nwords = vdev->notify_sz / 4;
unsigned int i;
u32 csum;
- if (!vdev->notify)
+ if (!vdev->notify || !vdev->notify_sz)
return 0;
do {
csum = 0;
- memcpy(&vdev->notify_copy, vdev->notify,
- sizeof(struct vnic_devcmd_notify));
+ memcpy(&vdev->notify_copy, vdev->notify, vdev->notify_sz);
words = (u32 *)&vdev->notify_copy;
for (i = 1; i < nwords; i++)
csum += words[i];
@@ -565,7 +575,20 @@ int vnic_dev_init(struct vnic_dev *vdev, int arg)
{
u64 a0 = (u32)arg, a1 = 0;
int wait = 1000;
- return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait);
+ int r = 0;
+
+ if (vnic_dev_capable(vdev, CMD_INIT))
+ r = vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait);
+ else {
+ vnic_dev_cmd(vdev, CMD_INIT_v1, &a0, &a1, wait);
+ if (a0 & CMD_INITF_DEFAULT_MAC) {
+ // Emulate these for old CMD_INIT_v1 which
+ // didn't pass a0 so no CMD_INITF_*.
+ vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait);
+ vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait);
+ }
+ }
+ return r;
}
int vnic_dev_link_status(struct vnic_dev *vdev)
@@ -666,3 +689,4 @@ err_out:
return NULL;
}
+
OpenPOWER on IntegriCloud