Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Scott Feldman and committed by
David S. Miller
27372bf5 86ca9db7

+60 -19
+42 -18
drivers/net/enic/vnic_dev.c
··· 43 43 struct vnic_devcmd_notify *notify; 44 44 struct vnic_devcmd_notify notify_copy; 45 45 dma_addr_t notify_pa; 46 + u32 notify_sz; 46 47 u32 *linkstatus; 47 48 dma_addr_t linkstatus_pa; 48 49 struct vnic_stats *stats; ··· 236 235 struct vnic_devcmd __iomem *devcmd = vdev->devcmd; 237 236 int delay; 238 237 u32 status; 239 - int dev_cmd_err[] = { 240 - /* convert from fw's version of error.h to host's version */ 241 - 0, /* ERR_SUCCESS */ 242 - EINVAL, /* ERR_EINVAL */ 243 - EFAULT, /* ERR_EFAULT */ 244 - EPERM, /* ERR_EPERM */ 245 - EBUSY, /* ERR_EBUSY */ 246 - }; 247 238 int err; 248 239 249 240 status = ioread32(&devcmd->status); ··· 263 270 if (!(status & STAT_BUSY)) { 264 271 265 272 if (status & STAT_ERROR) { 266 - err = dev_cmd_err[(int)readq(&devcmd->args[0])]; 267 - printk(KERN_ERR "Error %d devcmd %d\n", 268 - err, _CMD_N(cmd)); 269 - return -err; 273 + err = (int)readq(&devcmd->args[0]); 274 + if (err != ERR_ECMDUNKNOWN || 275 + cmd != CMD_CAPABILITY) 276 + printk(KERN_ERR "Error %d devcmd %d\n", 277 + err, _CMD_N(cmd)); 278 + return err; 270 279 } 271 280 272 281 if (_CMD_DIR(cmd) & _CMD_DIR_READ) { ··· 283 288 284 289 printk(KERN_ERR "Timedout devcmd %d\n", _CMD_N(cmd)); 285 290 return -ETIMEDOUT; 291 + } 292 + 293 + int vnic_dev_capable(struct vnic_dev *vdev, enum vnic_devcmd_cmd cmd) 294 + { 295 + u64 a0 = (u32)cmd, a1 = 0; 296 + int wait = 1000; 297 + int err; 298 + 299 + err = vnic_dev_cmd(vdev, CMD_CAPABILITY, &a0, &a1, wait); 300 + 301 + return !(err || a0); 286 302 } 287 303 288 304 int vnic_dev_fw_info(struct vnic_dev *vdev, ··· 517 511 { 518 512 u64 a0, a1; 519 513 int wait = 1000; 514 + int r; 520 515 521 516 if (!vdev->notify) { 522 517 vdev->notify = pci_alloc_consistent(vdev->pdev, ··· 525 518 &vdev->notify_pa); 526 519 if (!vdev->notify) 527 520 return -ENOMEM; 521 + memset(vdev->notify, 0, sizeof(struct vnic_devcmd_notify)); 528 522 } 529 523 530 524 a0 = vdev->notify_pa; 531 525 a1 = ((u64)intr << 32) & 0x0000ffff00000000ULL; 532 526 a1 += sizeof(struct vnic_devcmd_notify); 533 527 534 - return vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); 528 + r = vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); 529 + vdev->notify_sz = (r == 0) ? (u32)a1 : 0; 530 + return r; 535 531 } 536 532 537 533 void vnic_dev_notify_unset(struct vnic_dev *vdev) ··· 547 537 a1 += sizeof(struct vnic_devcmd_notify); 548 538 549 539 vnic_dev_cmd(vdev, CMD_NOTIFY, &a0, &a1, wait); 540 + vdev->notify_sz = 0; 550 541 } 551 542 552 543 static int vnic_dev_notify_ready(struct vnic_dev *vdev) 553 544 { 554 545 u32 *words; 555 - unsigned int nwords = sizeof(struct vnic_devcmd_notify) / 4; 546 + unsigned int nwords = vdev->notify_sz / 4; 556 547 unsigned int i; 557 548 u32 csum; 558 549 559 - if (!vdev->notify) 550 + if (!vdev->notify || !vdev->notify_sz) 560 551 return 0; 561 552 562 553 do { 563 554 csum = 0; 564 - memcpy(&vdev->notify_copy, vdev->notify, 565 - sizeof(struct vnic_devcmd_notify)); 555 + memcpy(&vdev->notify_copy, vdev->notify, vdev->notify_sz); 566 556 words = (u32 *)&vdev->notify_copy; 567 557 for (i = 1; i < nwords; i++) 568 558 csum += words[i]; ··· 575 565 { 576 566 u64 a0 = (u32)arg, a1 = 0; 577 567 int wait = 1000; 578 - return vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); 568 + int r = 0; 569 + 570 + if (vnic_dev_capable(vdev, CMD_INIT)) 571 + r = vnic_dev_cmd(vdev, CMD_INIT, &a0, &a1, wait); 572 + else { 573 + vnic_dev_cmd(vdev, CMD_INIT_v1, &a0, &a1, wait); 574 + if (a0 & CMD_INITF_DEFAULT_MAC) { 575 + // Emulate these for old CMD_INIT_v1 which 576 + // didn't pass a0 so no CMD_INITF_*. 577 + vnic_dev_cmd(vdev, CMD_MAC_ADDR, &a0, &a1, wait); 578 + vnic_dev_cmd(vdev, CMD_ADDR_ADD, &a0, &a1, wait); 579 + } 580 + } 581 + return r; 579 582 } 580 583 581 584 int vnic_dev_link_status(struct vnic_dev *vdev) ··· 688 665 vnic_dev_unregister(vdev); 689 666 return NULL; 690 667 } 668 + 691 669
+18 -1
drivers/net/enic/vnic_devcmd.h
··· 168 168 CMD_CLOSE = _CMDC(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 25), 169 169 170 170 /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ 171 - CMD_INIT = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), 171 + /***** Replaced by CMD_INIT *****/ 172 + CMD_INIT_v1 = _CMDCNW(_CMD_DIR_READ, _CMD_VTYPE_ALL, 26), 172 173 173 174 /* variant of CMD_INIT, with provisioning info 174 175 * (u64)a0=paddr of vnic_devcmd_provinfo ··· 199 198 200 199 /* undo initialize of virtual link */ 201 200 CMD_DEINIT = _CMDCNW(_CMD_DIR_NONE, _CMD_VTYPE_ALL, 34), 201 + 202 + /* initialize virtual link: (u32)a0=flags (see CMD_INITF_*) */ 203 + CMD_INIT = _CMDCNW(_CMD_DIR_WRITE, _CMD_VTYPE_ALL, 35), 204 + 205 + /* check fw capability of a cmd: 206 + * in: (u32)a0=cmd 207 + * out: (u32)a0=errno, 0:valid cmd, a1=supported VNIC_STF_* bits */ 208 + CMD_CAPABILITY = _CMDC(_CMD_DIR_RW, _CMD_VTYPE_ALL, 36), 202 209 }; 203 210 204 211 /* flags for CMD_OPEN */ ··· 258 249 u32 uif; /* uplink interface */ 259 250 u32 status; /* status bits (see VNIC_STF_*) */ 260 251 u32 error; /* error code (see ERR_*) for first ERR */ 252 + u32 link_down_cnt; /* running count of link down transitions */ 261 253 }; 262 254 #define VNIC_STF_FATAL_ERR 0x0001 /* fatal fw error */ 255 + #define VNIC_STF_STD_PAUSE 0x0002 /* standard link-level pause on */ 256 + #define VNIC_STF_PFC_PAUSE 0x0004 /* priority flow control pause on */ 257 + /* all supported status flags */ 258 + #define VNIC_STF_ALL (VNIC_STF_FATAL_ERR |\ 259 + VNIC_STF_STD_PAUSE |\ 260 + VNIC_STF_PFC_PAUSE |\ 261 + 0) 263 262 264 263 struct vnic_devcmd_provinfo { 265 264 u8 oui[3];