diff options
author | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
---|---|---|
committer | Glenn Elliott <gelliott@cs.unc.edu> | 2012-03-04 19:47:13 -0500 |
commit | c71c03bda1e86c9d5198c5d83f712e695c4f2a1e (patch) | |
tree | ecb166cb3e2b7e2adb3b5e292245fefd23381ac8 /drivers/net/qlcnic/qlcnic_hw.c | |
parent | ea53c912f8a86a8567697115b6a0d8152beee5c8 (diff) | |
parent | 6a00f206debf8a5c8899055726ad127dbeeed098 (diff) |
Merge branch 'mpi-master' into wip-k-fmlpwip-k-fmlp
Conflicts:
litmus/sched_cedf.c
Diffstat (limited to 'drivers/net/qlcnic/qlcnic_hw.c')
-rw-r--r-- | drivers/net/qlcnic/qlcnic_hw.c | 743 |
1 files changed, 609 insertions, 134 deletions
diff --git a/drivers/net/qlcnic/qlcnic_hw.c b/drivers/net/qlcnic/qlcnic_hw.c index e08c8b0556a4..a5d9fbf9d816 100644 --- a/drivers/net/qlcnic/qlcnic_hw.c +++ b/drivers/net/qlcnic/qlcnic_hw.c | |||
@@ -1,31 +1,15 @@ | |||
1 | /* | 1 | /* |
2 | * Copyright (C) 2009 - QLogic Corporation. | 2 | * QLogic qlcnic NIC Driver |
3 | * All rights reserved. | 3 | * Copyright (c) 2009-2010 QLogic Corporation |
4 | * | ||
5 | * This program is free software; you can redistribute it and/or | ||
6 | * modify it under the terms of the GNU General Public License | ||
7 | * as published by the Free Software Foundation; either version 2 | ||
8 | * of the License, or (at your option) any later version. | ||
9 | * | ||
10 | * This program is distributed in the hope that it will be useful, but | ||
11 | * WITHOUT ANY WARRANTY; without even the implied warranty of | ||
12 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
13 | * GNU General Public License for more details. | ||
14 | * | ||
15 | * You should have received a copy of the GNU General Public License | ||
16 | * along with this program; if not, write to the Free Software | ||
17 | * Foundation, Inc., 59 Temple Place - Suite 330, Boston, | ||
18 | * MA 02111-1307, USA. | ||
19 | * | ||
20 | * The full GNU General Public License is included in this distribution | ||
21 | * in the file called "COPYING". | ||
22 | * | 4 | * |
5 | * See LICENSE.qlcnic for copyright and licensing details. | ||
23 | */ | 6 | */ |
24 | 7 | ||
25 | #include "qlcnic.h" | 8 | #include "qlcnic.h" |
26 | 9 | ||
27 | #include <linux/slab.h> | 10 | #include <linux/slab.h> |
28 | #include <net/ip.h> | 11 | #include <net/ip.h> |
12 | #include <linux/bitops.h> | ||
29 | 13 | ||
30 | #define MASK(n) ((1ULL<<(n))-1) | 14 | #define MASK(n) ((1ULL<<(n))-1) |
31 | #define OCM_WIN_P3P(addr) (addr & 0xffc0000) | 15 | #define OCM_WIN_P3P(addr) (addr & 0xffc0000) |
@@ -297,8 +281,8 @@ qlcnic_pcie_sem_lock(struct qlcnic_adapter *adapter, int sem, u32 id_reg) | |||
297 | break; | 281 | break; |
298 | if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) { | 282 | if (++timeout >= QLCNIC_PCIE_SEM_TIMEOUT) { |
299 | dev_err(&adapter->pdev->dev, | 283 | dev_err(&adapter->pdev->dev, |
300 | "Failed to acquire sem=%d lock;reg_id=%d\n", | 284 | "Failed to acquire sem=%d lock; holdby=%d\n", |
301 | sem, id_reg); | 285 | sem, id_reg ? QLCRD32(adapter, id_reg) : -1); |
302 | return -EIO; | 286 | return -EIO; |
303 | } | 287 | } |
304 | msleep(1); | 288 | msleep(1); |
@@ -375,10 +359,11 @@ qlcnic_send_cmd_descs(struct qlcnic_adapter *adapter, | |||
375 | 359 | ||
376 | static int | 360 | static int |
377 | qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, | 361 | qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, |
378 | unsigned op) | 362 | __le16 vlan_id, unsigned op) |
379 | { | 363 | { |
380 | struct qlcnic_nic_req req; | 364 | struct qlcnic_nic_req req; |
381 | struct qlcnic_mac_req *mac_req; | 365 | struct qlcnic_mac_req *mac_req; |
366 | struct qlcnic_vlan_req *vlan_req; | ||
382 | u64 word; | 367 | u64 word; |
383 | 368 | ||
384 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); | 369 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
@@ -391,10 +376,13 @@ qlcnic_sre_macaddr_change(struct qlcnic_adapter *adapter, u8 *addr, | |||
391 | mac_req->op = op; | 376 | mac_req->op = op; |
392 | memcpy(mac_req->mac_addr, addr, 6); | 377 | memcpy(mac_req->mac_addr, addr, 6); |
393 | 378 | ||
379 | vlan_req = (struct qlcnic_vlan_req *)&req.words[1]; | ||
380 | vlan_req->vlan_id = vlan_id; | ||
381 | |||
394 | return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); | 382 | return qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); |
395 | } | 383 | } |
396 | 384 | ||
397 | static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, u8 *addr) | 385 | static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, const u8 *addr) |
398 | { | 386 | { |
399 | struct list_head *head; | 387 | struct list_head *head; |
400 | struct qlcnic_mac_list_s *cur; | 388 | struct qlcnic_mac_list_s *cur; |
@@ -415,7 +403,7 @@ static int qlcnic_nic_add_mac(struct qlcnic_adapter *adapter, u8 *addr) | |||
415 | memcpy(cur->mac_addr, addr, ETH_ALEN); | 403 | memcpy(cur->mac_addr, addr, ETH_ALEN); |
416 | 404 | ||
417 | if (qlcnic_sre_macaddr_change(adapter, | 405 | if (qlcnic_sre_macaddr_change(adapter, |
418 | cur->mac_addr, QLCNIC_MAC_ADD)) { | 406 | cur->mac_addr, 0, QLCNIC_MAC_ADD)) { |
419 | kfree(cur); | 407 | kfree(cur); |
420 | return -EIO; | 408 | return -EIO; |
421 | } | 409 | } |
@@ -428,7 +416,9 @@ void qlcnic_set_multi(struct net_device *netdev) | |||
428 | { | 416 | { |
429 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 417 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
430 | struct netdev_hw_addr *ha; | 418 | struct netdev_hw_addr *ha; |
431 | u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff }; | 419 | static const u8 bcast_addr[ETH_ALEN] = { |
420 | 0xff, 0xff, 0xff, 0xff, 0xff, 0xff | ||
421 | }; | ||
432 | u32 mode = VPORT_MISS_MODE_DROP; | 422 | u32 mode = VPORT_MISS_MODE_DROP; |
433 | 423 | ||
434 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) | 424 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) |
@@ -438,7 +428,8 @@ void qlcnic_set_multi(struct net_device *netdev) | |||
438 | qlcnic_nic_add_mac(adapter, bcast_addr); | 428 | qlcnic_nic_add_mac(adapter, bcast_addr); |
439 | 429 | ||
440 | if (netdev->flags & IFF_PROMISC) { | 430 | if (netdev->flags & IFF_PROMISC) { |
441 | mode = VPORT_MISS_MODE_ACCEPT_ALL; | 431 | if (!(adapter->flags & QLCNIC_PROMISC_DISABLED)) |
432 | mode = VPORT_MISS_MODE_ACCEPT_ALL; | ||
442 | goto send_fw_cmd; | 433 | goto send_fw_cmd; |
443 | } | 434 | } |
444 | 435 | ||
@@ -467,7 +458,7 @@ int qlcnic_nic_set_promisc(struct qlcnic_adapter *adapter, u32 mode) | |||
467 | 458 | ||
468 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); | 459 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
469 | 460 | ||
470 | word = QLCNIC_H2C_OPCODE_PROXY_SET_VPORT_MISS_MODE | | 461 | word = QLCNIC_H2C_OPCODE_SET_MAC_RECEIVE_MODE | |
471 | ((u64)adapter->portnum << 16); | 462 | ((u64)adapter->portnum << 16); |
472 | req.req_hdr = cpu_to_le64(word); | 463 | req.req_hdr = cpu_to_le64(word); |
473 | 464 | ||
@@ -485,13 +476,62 @@ void qlcnic_free_mac_list(struct qlcnic_adapter *adapter) | |||
485 | while (!list_empty(head)) { | 476 | while (!list_empty(head)) { |
486 | cur = list_entry(head->next, struct qlcnic_mac_list_s, list); | 477 | cur = list_entry(head->next, struct qlcnic_mac_list_s, list); |
487 | qlcnic_sre_macaddr_change(adapter, | 478 | qlcnic_sre_macaddr_change(adapter, |
488 | cur->mac_addr, QLCNIC_MAC_DEL); | 479 | cur->mac_addr, 0, QLCNIC_MAC_DEL); |
489 | list_del(&cur->list); | 480 | list_del(&cur->list); |
490 | kfree(cur); | 481 | kfree(cur); |
491 | } | 482 | } |
492 | } | 483 | } |
493 | 484 | ||
494 | #define QLCNIC_CONFIG_INTR_COALESCE 3 | 485 | void qlcnic_prune_lb_filters(struct qlcnic_adapter *adapter) |
486 | { | ||
487 | struct qlcnic_filter *tmp_fil; | ||
488 | struct hlist_node *tmp_hnode, *n; | ||
489 | struct hlist_head *head; | ||
490 | int i; | ||
491 | |||
492 | for (i = 0; i < adapter->fhash.fmax; i++) { | ||
493 | head = &(adapter->fhash.fhead[i]); | ||
494 | |||
495 | hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) | ||
496 | { | ||
497 | if (jiffies > | ||
498 | (QLCNIC_FILTER_AGE * HZ + tmp_fil->ftime)) { | ||
499 | qlcnic_sre_macaddr_change(adapter, | ||
500 | tmp_fil->faddr, tmp_fil->vlan_id, | ||
501 | tmp_fil->vlan_id ? QLCNIC_MAC_VLAN_DEL : | ||
502 | QLCNIC_MAC_DEL); | ||
503 | spin_lock_bh(&adapter->mac_learn_lock); | ||
504 | adapter->fhash.fnum--; | ||
505 | hlist_del(&tmp_fil->fnode); | ||
506 | spin_unlock_bh(&adapter->mac_learn_lock); | ||
507 | kfree(tmp_fil); | ||
508 | } | ||
509 | } | ||
510 | } | ||
511 | } | ||
512 | |||
513 | void qlcnic_delete_lb_filters(struct qlcnic_adapter *adapter) | ||
514 | { | ||
515 | struct qlcnic_filter *tmp_fil; | ||
516 | struct hlist_node *tmp_hnode, *n; | ||
517 | struct hlist_head *head; | ||
518 | int i; | ||
519 | |||
520 | for (i = 0; i < adapter->fhash.fmax; i++) { | ||
521 | head = &(adapter->fhash.fhead[i]); | ||
522 | |||
523 | hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) { | ||
524 | qlcnic_sre_macaddr_change(adapter, tmp_fil->faddr, | ||
525 | tmp_fil->vlan_id, tmp_fil->vlan_id ? | ||
526 | QLCNIC_MAC_VLAN_DEL : QLCNIC_MAC_DEL); | ||
527 | spin_lock_bh(&adapter->mac_learn_lock); | ||
528 | adapter->fhash.fnum--; | ||
529 | hlist_del(&tmp_fil->fnode); | ||
530 | spin_unlock_bh(&adapter->mac_learn_lock); | ||
531 | kfree(tmp_fil); | ||
532 | } | ||
533 | } | ||
534 | } | ||
495 | 535 | ||
496 | /* | 536 | /* |
497 | * Send the interrupt coalescing parameter set by ethtool to the card. | 537 | * Send the interrupt coalescing parameter set by ethtool to the card. |
@@ -499,25 +539,25 @@ void qlcnic_free_mac_list(struct qlcnic_adapter *adapter) | |||
499 | int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter) | 539 | int qlcnic_config_intr_coalesce(struct qlcnic_adapter *adapter) |
500 | { | 540 | { |
501 | struct qlcnic_nic_req req; | 541 | struct qlcnic_nic_req req; |
502 | u64 word[6]; | 542 | int rv; |
503 | int rv, i; | ||
504 | 543 | ||
505 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); | 544 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
506 | 545 | ||
507 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); | 546 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
508 | 547 | ||
509 | word[0] = QLCNIC_CONFIG_INTR_COALESCE | ((u64)adapter->portnum << 16); | 548 | req.req_hdr = cpu_to_le64(QLCNIC_CONFIG_INTR_COALESCE | |
510 | req.req_hdr = cpu_to_le64(word[0]); | 549 | ((u64) adapter->portnum << 16)); |
511 | |||
512 | memcpy(&word[0], &adapter->coal, sizeof(adapter->coal)); | ||
513 | for (i = 0; i < 6; i++) | ||
514 | req.words[i] = cpu_to_le64(word[i]); | ||
515 | 550 | ||
551 | req.words[0] = cpu_to_le64(((u64) adapter->ahw->coal.flag) << 32); | ||
552 | req.words[2] = cpu_to_le64(adapter->ahw->coal.rx_packets | | ||
553 | ((u64) adapter->ahw->coal.rx_time_us) << 16); | ||
554 | req.words[5] = cpu_to_le64(adapter->ahw->coal.timer_out | | ||
555 | ((u64) adapter->ahw->coal.type) << 32 | | ||
556 | ((u64) adapter->ahw->coal.sts_ring_mask) << 40); | ||
516 | rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); | 557 | rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); |
517 | if (rv != 0) | 558 | if (rv != 0) |
518 | dev_err(&adapter->netdev->dev, | 559 | dev_err(&adapter->netdev->dev, |
519 | "Could not send interrupt coalescing parameters\n"); | 560 | "Could not send interrupt coalescing parameters\n"); |
520 | |||
521 | return rv; | 561 | return rv; |
522 | } | 562 | } |
523 | 563 | ||
@@ -527,7 +567,7 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable) | |||
527 | u64 word; | 567 | u64 word; |
528 | int rv; | 568 | int rv; |
529 | 569 | ||
530 | if ((adapter->flags & QLCNIC_LRO_ENABLED) == enable) | 570 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) |
531 | return 0; | 571 | return 0; |
532 | 572 | ||
533 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); | 573 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
@@ -544,8 +584,6 @@ int qlcnic_config_hw_lro(struct qlcnic_adapter *adapter, int enable) | |||
544 | dev_err(&adapter->netdev->dev, | 584 | dev_err(&adapter->netdev->dev, |
545 | "Could not send configure hw lro request\n"); | 585 | "Could not send configure hw lro request\n"); |
546 | 586 | ||
547 | adapter->flags ^= QLCNIC_LRO_ENABLED; | ||
548 | |||
549 | return rv; | 587 | return rv; |
550 | } | 588 | } |
551 | 589 | ||
@@ -587,10 +625,11 @@ int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable) | |||
587 | u64 word; | 625 | u64 word; |
588 | int i, rv; | 626 | int i, rv; |
589 | 627 | ||
590 | const u64 key[] = { 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL, | 628 | static const u64 key[] = { |
591 | 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL, | 629 | 0xbeac01fa6a42b73bULL, 0x8030f20c77cb2da3ULL, |
592 | 0x255b0ec26d5a56daULL }; | 630 | 0xae7b30b4d0ca2bcbULL, 0x43a38fb04167253dULL, |
593 | 631 | 0x255b0ec26d5a56daULL | |
632 | }; | ||
594 | 633 | ||
595 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); | 634 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
596 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); | 635 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
@@ -623,9 +662,10 @@ int qlcnic_config_rss(struct qlcnic_adapter *adapter, int enable) | |||
623 | return rv; | 662 | return rv; |
624 | } | 663 | } |
625 | 664 | ||
626 | int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd) | 665 | int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, __be32 ip, int cmd) |
627 | { | 666 | { |
628 | struct qlcnic_nic_req req; | 667 | struct qlcnic_nic_req req; |
668 | struct qlcnic_ipaddr *ipa; | ||
629 | u64 word; | 669 | u64 word; |
630 | int rv; | 670 | int rv; |
631 | 671 | ||
@@ -636,7 +676,8 @@ int qlcnic_config_ipaddr(struct qlcnic_adapter *adapter, u32 ip, int cmd) | |||
636 | req.req_hdr = cpu_to_le64(word); | 676 | req.req_hdr = cpu_to_le64(word); |
637 | 677 | ||
638 | req.words[0] = cpu_to_le64(cmd); | 678 | req.words[0] = cpu_to_le64(cmd); |
639 | req.words[1] = cpu_to_le64(ip); | 679 | ipa = (struct qlcnic_ipaddr *)&req.words[1]; |
680 | ipa->ipv4 = ip; | ||
640 | 681 | ||
641 | rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); | 682 | rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); |
642 | if (rv != 0) | 683 | if (rv != 0) |
@@ -674,6 +715,9 @@ int qlcnic_send_lro_cleanup(struct qlcnic_adapter *adapter) | |||
674 | u64 word; | 715 | u64 word; |
675 | int rv; | 716 | int rv; |
676 | 717 | ||
718 | if (!test_bit(__QLCNIC_FW_ATTACHED, &adapter->state)) | ||
719 | return 0; | ||
720 | |||
677 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); | 721 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); |
678 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); | 722 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); |
679 | 723 | ||
@@ -701,9 +745,9 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu) | |||
701 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | 745 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
702 | int rc = 0; | 746 | int rc = 0; |
703 | 747 | ||
704 | if (mtu > P3_MAX_MTU) { | 748 | if (mtu < P3P_MIN_MTU || mtu > P3P_MAX_MTU) { |
705 | dev_err(&adapter->netdev->dev, "mtu > %d bytes unsupported\n", | 749 | dev_err(&adapter->netdev->dev, "%d bytes < mtu < %d bytes" |
706 | P3_MAX_MTU); | 750 | " not supported\n", P3P_MAX_MTU, P3P_MIN_MTU); |
707 | return -EINVAL; | 751 | return -EINVAL; |
708 | } | 752 | } |
709 | 753 | ||
@@ -715,15 +759,39 @@ int qlcnic_change_mtu(struct net_device *netdev, int mtu) | |||
715 | return rc; | 759 | return rc; |
716 | } | 760 | } |
717 | 761 | ||
718 | int qlcnic_get_mac_addr(struct qlcnic_adapter *adapter, u8 *mac) | 762 | |
763 | u32 qlcnic_fix_features(struct net_device *netdev, u32 features) | ||
764 | { | ||
765 | struct qlcnic_adapter *adapter = netdev_priv(netdev); | ||
766 | |||
767 | if ((adapter->flags & QLCNIC_ESWITCH_ENABLED)) { | ||
768 | u32 changed = features ^ netdev->features; | ||
769 | features ^= changed & (NETIF_F_ALL_CSUM | NETIF_F_RXCSUM); | ||
770 | } | ||
771 | |||
772 | if (!(features & NETIF_F_RXCSUM)) | ||
773 | features &= ~NETIF_F_LRO; | ||
774 | |||
775 | return features; | ||
776 | } | ||
777 | |||
778 | |||
779 | int qlcnic_set_features(struct net_device *netdev, u32 features) | ||
719 | { | 780 | { |
720 | u32 crbaddr; | 781 | struct qlcnic_adapter *adapter = netdev_priv(netdev); |
721 | int pci_func = adapter->ahw.pci_func; | 782 | u32 changed = netdev->features ^ features; |
783 | int hw_lro = (features & NETIF_F_LRO) ? QLCNIC_LRO_ENABLED : 0; | ||
784 | |||
785 | if (!(changed & NETIF_F_LRO)) | ||
786 | return 0; | ||
722 | 787 | ||
723 | crbaddr = CRB_MAC_BLOCK_START + | 788 | netdev->features = features ^ NETIF_F_LRO; |
724 | (4 * ((pci_func/2) * 3)) + (4 * (pci_func & 1)); | ||
725 | 789 | ||
726 | qlcnic_fetch_mac(adapter, crbaddr, crbaddr+4, pci_func & 1, mac); | 790 | if (qlcnic_config_hw_lro(adapter, hw_lro)) |
791 | return -EIO; | ||
792 | |||
793 | if ((hw_lro == 0) && qlcnic_send_lro_cleanup(adapter)) | ||
794 | return -EIO; | ||
727 | 795 | ||
728 | return 0; | 796 | return 0; |
729 | } | 797 | } |
@@ -754,7 +822,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter, | |||
754 | m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)]; | 822 | m = &crb_128M_2M_map[CRB_BLK(off)].sub_block[CRB_SUBBLK(off)]; |
755 | 823 | ||
756 | if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) { | 824 | if (m->valid && (m->start_128M <= off) && (m->end_128M > off)) { |
757 | *addr = adapter->ahw.pci_base0 + m->start_2M + | 825 | *addr = adapter->ahw->pci_base0 + m->start_2M + |
758 | (off - m->start_128M); | 826 | (off - m->start_128M); |
759 | return 0; | 827 | return 0; |
760 | } | 828 | } |
@@ -762,7 +830,7 @@ qlcnic_pci_get_crb_addr_2M(struct qlcnic_adapter *adapter, | |||
762 | /* | 830 | /* |
763 | * Not in direct map, use crb window | 831 | * Not in direct map, use crb window |
764 | */ | 832 | */ |
765 | *addr = adapter->ahw.pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); | 833 | *addr = adapter->ahw->pci_base0 + CRB_INDIRECT_2M + (off & MASK(16)); |
766 | return 1; | 834 | return 1; |
767 | } | 835 | } |
768 | 836 | ||
@@ -775,7 +843,7 @@ static int | |||
775 | qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off) | 843 | qlcnic_pci_set_crbwindow_2M(struct qlcnic_adapter *adapter, ulong off) |
776 | { | 844 | { |
777 | u32 window; | 845 | u32 window; |
778 | void __iomem *addr = adapter->ahw.pci_base0 + CRB_WINDOW_2M; | 846 | void __iomem *addr = adapter->ahw->pci_base0 + CRB_WINDOW_2M; |
779 | 847 | ||
780 | off -= QLCNIC_PCI_CRBSPACE; | 848 | off -= QLCNIC_PCI_CRBSPACE; |
781 | 849 | ||
@@ -812,13 +880,13 @@ qlcnic_hw_write_wx_2M(struct qlcnic_adapter *adapter, ulong off, u32 data) | |||
812 | 880 | ||
813 | if (rv > 0) { | 881 | if (rv > 0) { |
814 | /* indirect access */ | 882 | /* indirect access */ |
815 | write_lock_irqsave(&adapter->ahw.crb_lock, flags); | 883 | write_lock_irqsave(&adapter->ahw->crb_lock, flags); |
816 | crb_win_lock(adapter); | 884 | crb_win_lock(adapter); |
817 | rv = qlcnic_pci_set_crbwindow_2M(adapter, off); | 885 | rv = qlcnic_pci_set_crbwindow_2M(adapter, off); |
818 | if (!rv) | 886 | if (!rv) |
819 | writel(data, addr); | 887 | writel(data, addr); |
820 | crb_win_unlock(adapter); | 888 | crb_win_unlock(adapter); |
821 | write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); | 889 | write_unlock_irqrestore(&adapter->ahw->crb_lock, flags); |
822 | return rv; | 890 | return rv; |
823 | } | 891 | } |
824 | 892 | ||
@@ -843,12 +911,12 @@ qlcnic_hw_read_wx_2M(struct qlcnic_adapter *adapter, ulong off) | |||
843 | 911 | ||
844 | if (rv > 0) { | 912 | if (rv > 0) { |
845 | /* indirect access */ | 913 | /* indirect access */ |
846 | write_lock_irqsave(&adapter->ahw.crb_lock, flags); | 914 | write_lock_irqsave(&adapter->ahw->crb_lock, flags); |
847 | crb_win_lock(adapter); | 915 | crb_win_lock(adapter); |
848 | if (!qlcnic_pci_set_crbwindow_2M(adapter, off)) | 916 | if (!qlcnic_pci_set_crbwindow_2M(adapter, off)) |
849 | data = readl(addr); | 917 | data = readl(addr); |
850 | crb_win_unlock(adapter); | 918 | crb_win_unlock(adapter); |
851 | write_unlock_irqrestore(&adapter->ahw.crb_lock, flags); | 919 | write_unlock_irqrestore(&adapter->ahw->crb_lock, flags); |
852 | return data; | 920 | return data; |
853 | } | 921 | } |
854 | 922 | ||
@@ -878,9 +946,9 @@ qlcnic_pci_set_window_2M(struct qlcnic_adapter *adapter, | |||
878 | 946 | ||
879 | window = OCM_WIN_P3P(addr); | 947 | window = OCM_WIN_P3P(addr); |
880 | 948 | ||
881 | writel(window, adapter->ahw.ocm_win_crb); | 949 | writel(window, adapter->ahw->ocm_win_crb); |
882 | /* read back to flush */ | 950 | /* read back to flush */ |
883 | readl(adapter->ahw.ocm_win_crb); | 951 | readl(adapter->ahw->ocm_win_crb); |
884 | 952 | ||
885 | *start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr); | 953 | *start = QLCNIC_PCI_OCM0_2M + GET_MEM_OFFS_2M(addr); |
886 | return 0; | 954 | return 0; |
@@ -894,13 +962,13 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, | |||
894 | int ret; | 962 | int ret; |
895 | u32 start; | 963 | u32 start; |
896 | 964 | ||
897 | mutex_lock(&adapter->ahw.mem_lock); | 965 | mutex_lock(&adapter->ahw->mem_lock); |
898 | 966 | ||
899 | ret = qlcnic_pci_set_window_2M(adapter, off, &start); | 967 | ret = qlcnic_pci_set_window_2M(adapter, off, &start); |
900 | if (ret != 0) | 968 | if (ret != 0) |
901 | goto unlock; | 969 | goto unlock; |
902 | 970 | ||
903 | addr = adapter->ahw.pci_base0 + start; | 971 | addr = adapter->ahw->pci_base0 + start; |
904 | 972 | ||
905 | if (op == 0) /* read */ | 973 | if (op == 0) /* read */ |
906 | *data = readq(addr); | 974 | *data = readq(addr); |
@@ -908,7 +976,7 @@ qlcnic_pci_mem_access_direct(struct qlcnic_adapter *adapter, u64 off, | |||
908 | writeq(*data, addr); | 976 | writeq(*data, addr); |
909 | 977 | ||
910 | unlock: | 978 | unlock: |
911 | mutex_unlock(&adapter->ahw.mem_lock); | 979 | mutex_unlock(&adapter->ahw->mem_lock); |
912 | 980 | ||
913 | return ret; | 981 | return ret; |
914 | } | 982 | } |
@@ -916,23 +984,23 @@ unlock: | |||
916 | void | 984 | void |
917 | qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) | 985 | qlcnic_pci_camqm_read_2M(struct qlcnic_adapter *adapter, u64 off, u64 *data) |
918 | { | 986 | { |
919 | void __iomem *addr = adapter->ahw.pci_base0 + | 987 | void __iomem *addr = adapter->ahw->pci_base0 + |
920 | QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); | 988 | QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); |
921 | 989 | ||
922 | mutex_lock(&adapter->ahw.mem_lock); | 990 | mutex_lock(&adapter->ahw->mem_lock); |
923 | *data = readq(addr); | 991 | *data = readq(addr); |
924 | mutex_unlock(&adapter->ahw.mem_lock); | 992 | mutex_unlock(&adapter->ahw->mem_lock); |
925 | } | 993 | } |
926 | 994 | ||
927 | void | 995 | void |
928 | qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data) | 996 | qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data) |
929 | { | 997 | { |
930 | void __iomem *addr = adapter->ahw.pci_base0 + | 998 | void __iomem *addr = adapter->ahw->pci_base0 + |
931 | QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); | 999 | QLCNIC_PCI_CAMQM_2M_BASE + (off - QLCNIC_PCI_CAMQM); |
932 | 1000 | ||
933 | mutex_lock(&adapter->ahw.mem_lock); | 1001 | mutex_lock(&adapter->ahw->mem_lock); |
934 | writeq(data, addr); | 1002 | writeq(data, addr); |
935 | mutex_unlock(&adapter->ahw.mem_lock); | 1003 | mutex_unlock(&adapter->ahw->mem_lock); |
936 | } | 1004 | } |
937 | 1005 | ||
938 | #define MAX_CTL_CHECK 1000 | 1006 | #define MAX_CTL_CHECK 1000 |
@@ -971,7 +1039,7 @@ qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter, | |||
971 | correct: | 1039 | correct: |
972 | off8 = off & ~0xf; | 1040 | off8 = off & ~0xf; |
973 | 1041 | ||
974 | mutex_lock(&adapter->ahw.mem_lock); | 1042 | mutex_lock(&adapter->ahw->mem_lock); |
975 | 1043 | ||
976 | writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); | 1044 | writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); |
977 | writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); | 1045 | writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); |
@@ -1023,7 +1091,7 @@ correct: | |||
1023 | ret = 0; | 1091 | ret = 0; |
1024 | 1092 | ||
1025 | done: | 1093 | done: |
1026 | mutex_unlock(&adapter->ahw.mem_lock); | 1094 | mutex_unlock(&adapter->ahw->mem_lock); |
1027 | 1095 | ||
1028 | return ret; | 1096 | return ret; |
1029 | } | 1097 | } |
@@ -1065,7 +1133,7 @@ qlcnic_pci_mem_read_2M(struct qlcnic_adapter *adapter, | |||
1065 | correct: | 1133 | correct: |
1066 | off8 = off & ~0xf; | 1134 | off8 = off & ~0xf; |
1067 | 1135 | ||
1068 | mutex_lock(&adapter->ahw.mem_lock); | 1136 | mutex_lock(&adapter->ahw->mem_lock); |
1069 | 1137 | ||
1070 | writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); | 1138 | writel(off8, (mem_crb + MIU_TEST_AGT_ADDR_LO)); |
1071 | writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); | 1139 | writel(0, (mem_crb + MIU_TEST_AGT_ADDR_HI)); |
@@ -1095,7 +1163,7 @@ correct: | |||
1095 | ret = 0; | 1163 | ret = 0; |
1096 | } | 1164 | } |
1097 | 1165 | ||
1098 | mutex_unlock(&adapter->ahw.mem_lock); | 1166 | mutex_unlock(&adapter->ahw->mem_lock); |
1099 | 1167 | ||
1100 | return ret; | 1168 | return ret; |
1101 | } | 1169 | } |
@@ -1119,39 +1187,39 @@ int qlcnic_get_board_info(struct qlcnic_adapter *adapter) | |||
1119 | if (qlcnic_rom_fast_read(adapter, offset, &board_type)) | 1187 | if (qlcnic_rom_fast_read(adapter, offset, &board_type)) |
1120 | return -EIO; | 1188 | return -EIO; |
1121 | 1189 | ||
1122 | adapter->ahw.board_type = board_type; | 1190 | adapter->ahw->board_type = board_type; |
1123 | 1191 | ||
1124 | if (board_type == QLCNIC_BRDTYPE_P3_4_GB_MM) { | 1192 | if (board_type == QLCNIC_BRDTYPE_P3P_4_GB_MM) { |
1125 | u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I); | 1193 | u32 gpio = QLCRD32(adapter, QLCNIC_ROMUSB_GLB_PAD_GPIO_I); |
1126 | if ((gpio & 0x8000) == 0) | 1194 | if ((gpio & 0x8000) == 0) |
1127 | board_type = QLCNIC_BRDTYPE_P3_10G_TP; | 1195 | board_type = QLCNIC_BRDTYPE_P3P_10G_TP; |
1128 | } | 1196 | } |
1129 | 1197 | ||
1130 | switch (board_type) { | 1198 | switch (board_type) { |
1131 | case QLCNIC_BRDTYPE_P3_HMEZ: | 1199 | case QLCNIC_BRDTYPE_P3P_HMEZ: |
1132 | case QLCNIC_BRDTYPE_P3_XG_LOM: | 1200 | case QLCNIC_BRDTYPE_P3P_XG_LOM: |
1133 | case QLCNIC_BRDTYPE_P3_10G_CX4: | 1201 | case QLCNIC_BRDTYPE_P3P_10G_CX4: |
1134 | case QLCNIC_BRDTYPE_P3_10G_CX4_LP: | 1202 | case QLCNIC_BRDTYPE_P3P_10G_CX4_LP: |
1135 | case QLCNIC_BRDTYPE_P3_IMEZ: | 1203 | case QLCNIC_BRDTYPE_P3P_IMEZ: |
1136 | case QLCNIC_BRDTYPE_P3_10G_SFP_PLUS: | 1204 | case QLCNIC_BRDTYPE_P3P_10G_SFP_PLUS: |
1137 | case QLCNIC_BRDTYPE_P3_10G_SFP_CT: | 1205 | case QLCNIC_BRDTYPE_P3P_10G_SFP_CT: |
1138 | case QLCNIC_BRDTYPE_P3_10G_SFP_QT: | 1206 | case QLCNIC_BRDTYPE_P3P_10G_SFP_QT: |
1139 | case QLCNIC_BRDTYPE_P3_10G_XFP: | 1207 | case QLCNIC_BRDTYPE_P3P_10G_XFP: |
1140 | case QLCNIC_BRDTYPE_P3_10000_BASE_T: | 1208 | case QLCNIC_BRDTYPE_P3P_10000_BASE_T: |
1141 | adapter->ahw.port_type = QLCNIC_XGBE; | 1209 | adapter->ahw->port_type = QLCNIC_XGBE; |
1142 | break; | 1210 | break; |
1143 | case QLCNIC_BRDTYPE_P3_REF_QG: | 1211 | case QLCNIC_BRDTYPE_P3P_REF_QG: |
1144 | case QLCNIC_BRDTYPE_P3_4_GB: | 1212 | case QLCNIC_BRDTYPE_P3P_4_GB: |
1145 | case QLCNIC_BRDTYPE_P3_4_GB_MM: | 1213 | case QLCNIC_BRDTYPE_P3P_4_GB_MM: |
1146 | adapter->ahw.port_type = QLCNIC_GBE; | 1214 | adapter->ahw->port_type = QLCNIC_GBE; |
1147 | break; | 1215 | break; |
1148 | case QLCNIC_BRDTYPE_P3_10G_TP: | 1216 | case QLCNIC_BRDTYPE_P3P_10G_TP: |
1149 | adapter->ahw.port_type = (adapter->portnum < 2) ? | 1217 | adapter->ahw->port_type = (adapter->portnum < 2) ? |
1150 | QLCNIC_XGBE : QLCNIC_GBE; | 1218 | QLCNIC_XGBE : QLCNIC_GBE; |
1151 | break; | 1219 | break; |
1152 | default: | 1220 | default: |
1153 | dev_err(&pdev->dev, "unknown board type %x\n", board_type); | 1221 | dev_err(&pdev->dev, "unknown board type %x\n", board_type); |
1154 | adapter->ahw.port_type = QLCNIC_XGBE; | 1222 | adapter->ahw->port_type = QLCNIC_XGBE; |
1155 | break; | 1223 | break; |
1156 | } | 1224 | } |
1157 | 1225 | ||
@@ -1195,54 +1263,461 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate) | |||
1195 | return rv; | 1263 | return rv; |
1196 | } | 1264 | } |
1197 | 1265 | ||
1198 | static int qlcnic_set_fw_loopback(struct qlcnic_adapter *adapter, u32 flag) | 1266 | /* FW dump related functions */ |
1267 | static u32 | ||
1268 | qlcnic_dump_crb(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, | ||
1269 | u32 *buffer) | ||
1199 | { | 1270 | { |
1200 | struct qlcnic_nic_req req; | 1271 | int i; |
1201 | int rv; | 1272 | u32 addr, data; |
1202 | u64 word; | 1273 | struct __crb *crb = &entry->region.crb; |
1274 | void __iomem *base = adapter->ahw->pci_base0; | ||
1275 | |||
1276 | addr = crb->addr; | ||
1277 | |||
1278 | for (i = 0; i < crb->no_ops; i++) { | ||
1279 | QLCNIC_RD_DUMP_REG(addr, base, &data); | ||
1280 | *buffer++ = cpu_to_le32(addr); | ||
1281 | *buffer++ = cpu_to_le32(data); | ||
1282 | addr += crb->stride; | ||
1283 | } | ||
1284 | return crb->no_ops * 2 * sizeof(u32); | ||
1285 | } | ||
1203 | 1286 | ||
1204 | memset(&req, 0, sizeof(struct qlcnic_nic_req)); | 1287 | static u32 |
1205 | req.qhdr = cpu_to_le64(QLCNIC_HOST_REQUEST << 23); | 1288 | qlcnic_dump_ctrl(struct qlcnic_adapter *adapter, |
1289 | struct qlcnic_dump_entry *entry, u32 *buffer) | ||
1290 | { | ||
1291 | int i, k, timeout = 0; | ||
1292 | void __iomem *base = adapter->ahw->pci_base0; | ||
1293 | u32 addr, data; | ||
1294 | u8 opcode, no_ops; | ||
1295 | struct __ctrl *ctr = &entry->region.ctrl; | ||
1296 | struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr; | ||
1297 | |||
1298 | addr = ctr->addr; | ||
1299 | no_ops = ctr->no_ops; | ||
1300 | |||
1301 | for (i = 0; i < no_ops; i++) { | ||
1302 | k = 0; | ||
1303 | opcode = 0; | ||
1304 | for (k = 0; k < 8; k++) { | ||
1305 | if (!(ctr->opcode & (1 << k))) | ||
1306 | continue; | ||
1307 | switch (1 << k) { | ||
1308 | case QLCNIC_DUMP_WCRB: | ||
1309 | QLCNIC_WR_DUMP_REG(addr, base, ctr->val1); | ||
1310 | break; | ||
1311 | case QLCNIC_DUMP_RWCRB: | ||
1312 | QLCNIC_RD_DUMP_REG(addr, base, &data); | ||
1313 | QLCNIC_WR_DUMP_REG(addr, base, data); | ||
1314 | break; | ||
1315 | case QLCNIC_DUMP_ANDCRB: | ||
1316 | QLCNIC_RD_DUMP_REG(addr, base, &data); | ||
1317 | QLCNIC_WR_DUMP_REG(addr, base, | ||
1318 | (data & ctr->val2)); | ||
1319 | break; | ||
1320 | case QLCNIC_DUMP_ORCRB: | ||
1321 | QLCNIC_RD_DUMP_REG(addr, base, &data); | ||
1322 | QLCNIC_WR_DUMP_REG(addr, base, | ||
1323 | (data | ctr->val3)); | ||
1324 | break; | ||
1325 | case QLCNIC_DUMP_POLLCRB: | ||
1326 | while (timeout <= ctr->timeout) { | ||
1327 | QLCNIC_RD_DUMP_REG(addr, base, &data); | ||
1328 | if ((data & ctr->val2) == ctr->val1) | ||
1329 | break; | ||
1330 | msleep(1); | ||
1331 | timeout++; | ||
1332 | } | ||
1333 | if (timeout > ctr->timeout) { | ||
1334 | dev_info(&adapter->pdev->dev, | ||
1335 | "Timed out, aborting poll CRB\n"); | ||
1336 | return -EINVAL; | ||
1337 | } | ||
1338 | break; | ||
1339 | case QLCNIC_DUMP_RD_SAVE: | ||
1340 | if (ctr->index_a) | ||
1341 | addr = t_hdr->saved_state[ctr->index_a]; | ||
1342 | QLCNIC_RD_DUMP_REG(addr, base, &data); | ||
1343 | t_hdr->saved_state[ctr->index_v] = data; | ||
1344 | break; | ||
1345 | case QLCNIC_DUMP_WRT_SAVED: | ||
1346 | if (ctr->index_v) | ||
1347 | data = t_hdr->saved_state[ctr->index_v]; | ||
1348 | else | ||
1349 | data = ctr->val1; | ||
1350 | if (ctr->index_a) | ||
1351 | addr = t_hdr->saved_state[ctr->index_a]; | ||
1352 | QLCNIC_WR_DUMP_REG(addr, base, data); | ||
1353 | break; | ||
1354 | case QLCNIC_DUMP_MOD_SAVE_ST: | ||
1355 | data = t_hdr->saved_state[ctr->index_v]; | ||
1356 | data <<= ctr->shl_val; | ||
1357 | data >>= ctr->shr_val; | ||
1358 | if (ctr->val2) | ||
1359 | data &= ctr->val2; | ||
1360 | data |= ctr->val3; | ||
1361 | data += ctr->val1; | ||
1362 | t_hdr->saved_state[ctr->index_v] = data; | ||
1363 | break; | ||
1364 | default: | ||
1365 | dev_info(&adapter->pdev->dev, | ||
1366 | "Unknown opcode\n"); | ||
1367 | break; | ||
1368 | } | ||
1369 | } | ||
1370 | addr += ctr->stride; | ||
1371 | } | ||
1372 | return 0; | ||
1373 | } | ||
1206 | 1374 | ||
1207 | word = QLCNIC_H2C_OPCODE_CONFIG_LOOPBACK | | 1375 | static u32 |
1208 | ((u64)adapter->portnum << 16); | 1376 | qlcnic_dump_mux(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, |
1209 | req.req_hdr = cpu_to_le64(word); | 1377 | u32 *buffer) |
1210 | req.words[0] = cpu_to_le64(flag); | 1378 | { |
1379 | int loop; | ||
1380 | u32 val, data = 0; | ||
1381 | struct __mux *mux = &entry->region.mux; | ||
1382 | void __iomem *base = adapter->ahw->pci_base0; | ||
1383 | |||
1384 | val = mux->val; | ||
1385 | for (loop = 0; loop < mux->no_ops; loop++) { | ||
1386 | QLCNIC_WR_DUMP_REG(mux->addr, base, val); | ||
1387 | QLCNIC_RD_DUMP_REG(mux->read_addr, base, &data); | ||
1388 | *buffer++ = cpu_to_le32(val); | ||
1389 | *buffer++ = cpu_to_le32(data); | ||
1390 | val += mux->val_stride; | ||
1391 | } | ||
1392 | return 2 * mux->no_ops * sizeof(u32); | ||
1393 | } | ||
1211 | 1394 | ||
1212 | rv = qlcnic_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1); | 1395 | static u32 |
1213 | if (rv) | 1396 | qlcnic_dump_que(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, |
1214 | dev_err(&adapter->pdev->dev, | 1397 | u32 *buffer) |
1215 | "%sting loopback mode failed.\n", | 1398 | { |
1216 | flag ? "Set" : "Reset"); | 1399 | int i, loop; |
1217 | return rv; | 1400 | u32 cnt, addr, data, que_id = 0; |
1401 | void __iomem *base = adapter->ahw->pci_base0; | ||
1402 | struct __queue *que = &entry->region.que; | ||
1403 | |||
1404 | addr = que->read_addr; | ||
1405 | cnt = que->read_addr_cnt; | ||
1406 | |||
1407 | for (loop = 0; loop < que->no_ops; loop++) { | ||
1408 | QLCNIC_WR_DUMP_REG(que->sel_addr, base, que_id); | ||
1409 | addr = que->read_addr; | ||
1410 | for (i = 0; i < cnt; i++) { | ||
1411 | QLCNIC_RD_DUMP_REG(addr, base, &data); | ||
1412 | *buffer++ = cpu_to_le32(data); | ||
1413 | addr += que->read_addr_stride; | ||
1414 | } | ||
1415 | que_id += que->stride; | ||
1416 | } | ||
1417 | return que->no_ops * cnt * sizeof(u32); | ||
1218 | } | 1418 | } |
1219 | 1419 | ||
1220 | int qlcnic_set_ilb_mode(struct qlcnic_adapter *adapter) | 1420 | static u32 |
1421 | qlcnic_dump_ocm(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, | ||
1422 | u32 *buffer) | ||
1221 | { | 1423 | { |
1222 | if (qlcnic_set_fw_loopback(adapter, 1)) | 1424 | int i; |
1223 | return -EIO; | 1425 | u32 data; |
1426 | void __iomem *addr; | ||
1427 | struct __ocm *ocm = &entry->region.ocm; | ||
1224 | 1428 | ||
1225 | if (qlcnic_nic_set_promisc(adapter, | 1429 | addr = adapter->ahw->pci_base0 + ocm->read_addr; |
1226 | VPORT_MISS_MODE_ACCEPT_ALL)) { | 1430 | for (i = 0; i < ocm->no_ops; i++) { |
1227 | qlcnic_set_fw_loopback(adapter, 0); | 1431 | data = readl(addr); |
1228 | return -EIO; | 1432 | *buffer++ = cpu_to_le32(data); |
1433 | addr += ocm->read_addr_stride; | ||
1229 | } | 1434 | } |
1435 | return ocm->no_ops * sizeof(u32); | ||
1436 | } | ||
1230 | 1437 | ||
1231 | msleep(1000); | 1438 | static u32 |
1232 | return 0; | 1439 | qlcnic_read_rom(struct qlcnic_adapter *adapter, struct qlcnic_dump_entry *entry, |
1440 | u32 *buffer) | ||
1441 | { | ||
1442 | int i, count = 0; | ||
1443 | u32 fl_addr, size, val, lck_val, addr; | ||
1444 | struct __mem *rom = &entry->region.mem; | ||
1445 | void __iomem *base = adapter->ahw->pci_base0; | ||
1446 | |||
1447 | fl_addr = rom->addr; | ||
1448 | size = rom->size/4; | ||
1449 | lock_try: | ||
1450 | lck_val = readl(base + QLCNIC_FLASH_SEM2_LK); | ||
1451 | if (!lck_val && count < MAX_CTL_CHECK) { | ||
1452 | msleep(10); | ||
1453 | count++; | ||
1454 | goto lock_try; | ||
1455 | } | ||
1456 | writel(adapter->ahw->pci_func, (base + QLCNIC_FLASH_LOCK_ID)); | ||
1457 | for (i = 0; i < size; i++) { | ||
1458 | addr = fl_addr & 0xFFFF0000; | ||
1459 | QLCNIC_WR_DUMP_REG(FLASH_ROM_WINDOW, base, addr); | ||
1460 | addr = LSW(fl_addr) + FLASH_ROM_DATA; | ||
1461 | QLCNIC_RD_DUMP_REG(addr, base, &val); | ||
1462 | fl_addr += 4; | ||
1463 | *buffer++ = cpu_to_le32(val); | ||
1464 | } | ||
1465 | readl(base + QLCNIC_FLASH_SEM2_ULK); | ||
1466 | return rom->size; | ||
1233 | } | 1467 | } |
1234 | 1468 | ||
1235 | void qlcnic_clear_ilb_mode(struct qlcnic_adapter *adapter) | 1469 | static u32 |
1470 | qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter, | ||
1471 | struct qlcnic_dump_entry *entry, u32 *buffer) | ||
1236 | { | 1472 | { |
1237 | int mode = VPORT_MISS_MODE_DROP; | 1473 | int i; |
1238 | struct net_device *netdev = adapter->netdev; | 1474 | u32 cnt, val, data, addr; |
1475 | void __iomem *base = adapter->ahw->pci_base0; | ||
1476 | struct __cache *l1 = &entry->region.cache; | ||
1477 | |||
1478 | val = l1->init_tag_val; | ||
1479 | |||
1480 | for (i = 0; i < l1->no_ops; i++) { | ||
1481 | QLCNIC_WR_DUMP_REG(l1->addr, base, val); | ||
1482 | QLCNIC_WR_DUMP_REG(l1->ctrl_addr, base, LSW(l1->ctrl_val)); | ||
1483 | addr = l1->read_addr; | ||
1484 | cnt = l1->read_addr_num; | ||
1485 | while (cnt) { | ||
1486 | QLCNIC_RD_DUMP_REG(addr, base, &data); | ||
1487 | *buffer++ = cpu_to_le32(data); | ||
1488 | addr += l1->read_addr_stride; | ||
1489 | cnt--; | ||
1490 | } | ||
1491 | val += l1->stride; | ||
1492 | } | ||
1493 | return l1->no_ops * l1->read_addr_num * sizeof(u32); | ||
1494 | } | ||
1239 | 1495 | ||
1240 | qlcnic_set_fw_loopback(adapter, 0); | 1496 | static u32 |
1497 | qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter, | ||
1498 | struct qlcnic_dump_entry *entry, u32 *buffer) | ||
1499 | { | ||
1500 | int i; | ||
1501 | u32 cnt, val, data, addr; | ||
1502 | u8 poll_mask, poll_to, time_out = 0; | ||
1503 | void __iomem *base = adapter->ahw->pci_base0; | ||
1504 | struct __cache *l2 = &entry->region.cache; | ||
1505 | |||
1506 | val = l2->init_tag_val; | ||
1507 | poll_mask = LSB(MSW(l2->ctrl_val)); | ||
1508 | poll_to = MSB(MSW(l2->ctrl_val)); | ||
1509 | |||
1510 | for (i = 0; i < l2->no_ops; i++) { | ||
1511 | QLCNIC_WR_DUMP_REG(l2->addr, base, val); | ||
1512 | do { | ||
1513 | QLCNIC_WR_DUMP_REG(l2->ctrl_addr, base, | ||
1514 | LSW(l2->ctrl_val)); | ||
1515 | QLCNIC_RD_DUMP_REG(l2->ctrl_addr, base, &data); | ||
1516 | if (!(data & poll_mask)) | ||
1517 | break; | ||
1518 | msleep(1); | ||
1519 | time_out++; | ||
1520 | } while (time_out <= poll_to); | ||
1521 | if (time_out > poll_to) | ||
1522 | return -EINVAL; | ||
1523 | |||
1524 | addr = l2->read_addr; | ||
1525 | cnt = l2->read_addr_num; | ||
1526 | while (cnt) { | ||
1527 | QLCNIC_RD_DUMP_REG(addr, base, &data); | ||
1528 | *buffer++ = cpu_to_le32(data); | ||
1529 | addr += l2->read_addr_stride; | ||
1530 | cnt--; | ||
1531 | } | ||
1532 | val += l2->stride; | ||
1533 | } | ||
1534 | return l2->no_ops * l2->read_addr_num * sizeof(u32); | ||
1535 | } | ||
1241 | 1536 | ||
1242 | if (netdev->flags & IFF_PROMISC) | 1537 | static u32 |
1243 | mode = VPORT_MISS_MODE_ACCEPT_ALL; | 1538 | qlcnic_read_memory(struct qlcnic_adapter *adapter, |
1244 | else if (netdev->flags & IFF_ALLMULTI) | 1539 | struct qlcnic_dump_entry *entry, u32 *buffer) |
1245 | mode = VPORT_MISS_MODE_ACCEPT_MULTI; | 1540 | { |
1541 | u32 addr, data, test, ret = 0; | ||
1542 | int i, reg_read; | ||
1543 | struct __mem *mem = &entry->region.mem; | ||
1544 | void __iomem *base = adapter->ahw->pci_base0; | ||
1545 | |||
1546 | reg_read = mem->size; | ||
1547 | addr = mem->addr; | ||
1548 | /* check for data size of multiple of 16 and 16 byte alignment */ | ||
1549 | if ((addr & 0xf) || (reg_read%16)) { | ||
1550 | dev_info(&adapter->pdev->dev, | ||
1551 | "Unaligned memory addr:0x%x size:0x%x\n", | ||
1552 | addr, reg_read); | ||
1553 | return -EINVAL; | ||
1554 | } | ||
1246 | 1555 | ||
1247 | qlcnic_nic_set_promisc(adapter, mode); | 1556 | mutex_lock(&adapter->ahw->mem_lock); |
1557 | |||
1558 | while (reg_read != 0) { | ||
1559 | QLCNIC_WR_DUMP_REG(MIU_TEST_ADDR_LO, base, addr); | ||
1560 | QLCNIC_WR_DUMP_REG(MIU_TEST_ADDR_HI, base, 0); | ||
1561 | QLCNIC_WR_DUMP_REG(MIU_TEST_CTR, base, | ||
1562 | TA_CTL_ENABLE | TA_CTL_START); | ||
1563 | |||
1564 | for (i = 0; i < MAX_CTL_CHECK; i++) { | ||
1565 | QLCNIC_RD_DUMP_REG(MIU_TEST_CTR, base, &test); | ||
1566 | if (!(test & TA_CTL_BUSY)) | ||
1567 | break; | ||
1568 | } | ||
1569 | if (i == MAX_CTL_CHECK) { | ||
1570 | if (printk_ratelimit()) { | ||
1571 | dev_err(&adapter->pdev->dev, | ||
1572 | "failed to read through agent\n"); | ||
1573 | ret = -EINVAL; | ||
1574 | goto out; | ||
1575 | } | ||
1576 | } | ||
1577 | for (i = 0; i < 4; i++) { | ||
1578 | QLCNIC_RD_DUMP_REG(MIU_TEST_READ_DATA[i], base, &data); | ||
1579 | *buffer++ = cpu_to_le32(data); | ||
1580 | } | ||
1581 | addr += 16; | ||
1582 | reg_read -= 16; | ||
1583 | ret += 16; | ||
1584 | } | ||
1585 | out: | ||
1586 | mutex_unlock(&adapter->ahw->mem_lock); | ||
1587 | return mem->size; | ||
1588 | } | ||
1589 | |||
1590 | static u32 | ||
1591 | qlcnic_dump_nop(struct qlcnic_adapter *adapter, | ||
1592 | struct qlcnic_dump_entry *entry, u32 *buffer) | ||
1593 | { | ||
1594 | entry->hdr.flags |= QLCNIC_DUMP_SKIP; | ||
1595 | return 0; | ||
1596 | } | ||
1597 | |||
1598 | struct qlcnic_dump_operations fw_dump_ops[] = { | ||
1599 | { QLCNIC_DUMP_NOP, qlcnic_dump_nop }, | ||
1600 | { QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb }, | ||
1601 | { QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux }, | ||
1602 | { QLCNIC_DUMP_QUEUE, qlcnic_dump_que }, | ||
1603 | { QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom }, | ||
1604 | { QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm }, | ||
1605 | { QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl }, | ||
1606 | { QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache }, | ||
1607 | { QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache }, | ||
1608 | { QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache }, | ||
1609 | { QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache }, | ||
1610 | { QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache }, | ||
1611 | { QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache }, | ||
1612 | { QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache }, | ||
1613 | { QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache }, | ||
1614 | { QLCNIC_DUMP_READ_ROM, qlcnic_read_rom }, | ||
1615 | { QLCNIC_DUMP_READ_MEM, qlcnic_read_memory }, | ||
1616 | { QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl }, | ||
1617 | { QLCNIC_DUMP_TLHDR, qlcnic_dump_nop }, | ||
1618 | { QLCNIC_DUMP_RDEND, qlcnic_dump_nop }, | ||
1619 | }; | ||
1620 | |||
1621 | /* Walk the template and collect dump for each entry in the dump template */ | ||
1622 | static int | ||
1623 | qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry, | ||
1624 | u32 size) | ||
1625 | { | ||
1626 | int ret = 1; | ||
1627 | if (size != entry->hdr.cap_size) { | ||
1628 | dev_info(dev, | ||
1629 | "Invalidate dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n", | ||
1630 | entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size); | ||
1631 | dev_info(dev, "Aborting further dump capture\n"); | ||
1632 | ret = 0; | ||
1633 | } | ||
1634 | return ret; | ||
1635 | } | ||
1636 | |||
1637 | int qlcnic_dump_fw(struct qlcnic_adapter *adapter) | ||
1638 | { | ||
1639 | u32 *buffer; | ||
1640 | char mesg[64]; | ||
1641 | char *msg[] = {mesg, NULL}; | ||
1642 | int i, k, ops_cnt, ops_index, dump_size = 0; | ||
1643 | u32 entry_offset, dump, no_entries, buf_offset = 0; | ||
1644 | struct qlcnic_dump_entry *entry; | ||
1645 | struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump; | ||
1646 | struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr; | ||
1647 | |||
1648 | if (fw_dump->clr) { | ||
1649 | dev_info(&adapter->pdev->dev, | ||
1650 | "Previous dump not cleared, not capturing dump\n"); | ||
1651 | return -EIO; | ||
1652 | } | ||
1653 | /* Calculate the size for dump data area only */ | ||
1654 | for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++) | ||
1655 | if (i & tmpl_hdr->drv_cap_mask) | ||
1656 | dump_size += tmpl_hdr->cap_sizes[k]; | ||
1657 | if (!dump_size) | ||
1658 | return -EIO; | ||
1659 | |||
1660 | fw_dump->data = vzalloc(dump_size); | ||
1661 | if (!fw_dump->data) { | ||
1662 | dev_info(&adapter->pdev->dev, | ||
1663 | "Unable to allocate (%d KB) for fw dump\n", | ||
1664 | dump_size/1024); | ||
1665 | return -ENOMEM; | ||
1666 | } | ||
1667 | buffer = fw_dump->data; | ||
1668 | fw_dump->size = dump_size; | ||
1669 | no_entries = tmpl_hdr->num_entries; | ||
1670 | ops_cnt = ARRAY_SIZE(fw_dump_ops); | ||
1671 | entry_offset = tmpl_hdr->offset; | ||
1672 | tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION; | ||
1673 | tmpl_hdr->sys_info[1] = adapter->fw_version; | ||
1674 | |||
1675 | for (i = 0; i < no_entries; i++) { | ||
1676 | entry = (struct qlcnic_dump_entry *) ((void *) tmpl_hdr + | ||
1677 | entry_offset); | ||
1678 | if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) { | ||
1679 | entry->hdr.flags |= QLCNIC_DUMP_SKIP; | ||
1680 | entry_offset += entry->hdr.offset; | ||
1681 | continue; | ||
1682 | } | ||
1683 | /* Find the handler for this entry */ | ||
1684 | ops_index = 0; | ||
1685 | while (ops_index < ops_cnt) { | ||
1686 | if (entry->hdr.type == fw_dump_ops[ops_index].opcode) | ||
1687 | break; | ||
1688 | ops_index++; | ||
1689 | } | ||
1690 | if (ops_index == ops_cnt) { | ||
1691 | dev_info(&adapter->pdev->dev, | ||
1692 | "Invalid entry type %d, exiting dump\n", | ||
1693 | entry->hdr.type); | ||
1694 | goto error; | ||
1695 | } | ||
1696 | /* Collect dump for this entry */ | ||
1697 | dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer); | ||
1698 | if (dump && !qlcnic_valid_dump_entry(&adapter->pdev->dev, entry, | ||
1699 | dump)) | ||
1700 | entry->hdr.flags |= QLCNIC_DUMP_SKIP; | ||
1701 | buf_offset += entry->hdr.cap_size; | ||
1702 | entry_offset += entry->hdr.offset; | ||
1703 | buffer = fw_dump->data + buf_offset; | ||
1704 | } | ||
1705 | if (dump_size != buf_offset) { | ||
1706 | dev_info(&adapter->pdev->dev, | ||
1707 | "Captured(%d) and expected size(%d) do not match\n", | ||
1708 | buf_offset, dump_size); | ||
1709 | goto error; | ||
1710 | } else { | ||
1711 | fw_dump->clr = 1; | ||
1712 | snprintf(mesg, sizeof(mesg), "FW dump for device: %d\n", | ||
1713 | adapter->pdev->devfn); | ||
1714 | dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n", | ||
1715 | fw_dump->size); | ||
1716 | /* Send a udev event to notify availability of FW dump */ | ||
1717 | kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg); | ||
1718 | return 0; | ||
1719 | } | ||
1720 | error: | ||
1721 | vfree(fw_dump->data); | ||
1722 | return -EINVAL; | ||
1248 | } | 1723 | } |