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