diff options
author | Dhananjay Phadke <dhananjay@netxen.com> | 2009-04-07 18:50:42 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-04-08 18:58:27 -0400 |
commit | 3bf26ce3f4cc3c9e0d0478b4016c6113a16faaf1 (patch) | |
tree | 8478804493b6e749a6e61870c8c3b5b9549469ad /drivers/net/netxen/netxen_nic_init.c | |
parent | 56a007871a6689db80e19f63fe6dc3692daa2a6f (diff) |
netxen: async link event handling
Add support for asynchronous events from firmware,
received over one of the rx rings.
Add support for event based phy interrupts, enhanced links
status reporting from firmware.
Signed-off-by: Dhananjay Phadke <dhananjay@netxen.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/netxen/netxen_nic_init.c')
-rw-r--r-- | drivers/net/netxen/netxen_nic_init.c | 102 |
1 files changed, 96 insertions, 6 deletions
diff --git a/drivers/net/netxen/netxen_nic_init.c b/drivers/net/netxen/netxen_nic_init.c index 9991951e6e05..974783c45321 100644 --- a/drivers/net/netxen/netxen_nic_init.c +++ b/drivers/net/netxen/netxen_nic_init.c | |||
@@ -795,9 +795,81 @@ int netxen_init_firmware(struct netxen_adapter *adapter) | |||
795 | adapter->pci_write_normalize(adapter, | 795 | adapter->pci_write_normalize(adapter, |
796 | CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); | 796 | CRB_CMDPEG_STATE, PHAN_INITIALIZE_ACK); |
797 | 797 | ||
798 | if (adapter->fw_version >= NETXEN_VERSION_CODE(4, 0, 222)) { | ||
799 | adapter->capabilities = netxen_nic_reg_read(adapter, | ||
800 | CRB_FW_CAPABILITIES_1); | ||
801 | } | ||
802 | |||
798 | return err; | 803 | return err; |
799 | } | 804 | } |
800 | 805 | ||
806 | static void | ||
807 | netxen_handle_linkevent(struct netxen_adapter *adapter, nx_fw_msg_t *msg) | ||
808 | { | ||
809 | u32 cable_OUI; | ||
810 | u16 cable_len; | ||
811 | u16 link_speed; | ||
812 | u8 link_status, module, duplex, autoneg; | ||
813 | struct net_device *netdev = adapter->netdev; | ||
814 | |||
815 | adapter->has_link_events = 1; | ||
816 | |||
817 | cable_OUI = msg->body[1] & 0xffffffff; | ||
818 | cable_len = (msg->body[1] >> 32) & 0xffff; | ||
819 | link_speed = (msg->body[1] >> 48) & 0xffff; | ||
820 | |||
821 | link_status = msg->body[2] & 0xff; | ||
822 | duplex = (msg->body[2] >> 16) & 0xff; | ||
823 | autoneg = (msg->body[2] >> 24) & 0xff; | ||
824 | |||
825 | module = (msg->body[2] >> 8) & 0xff; | ||
826 | if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE) { | ||
827 | printk(KERN_INFO "%s: unsupported cable: OUI 0x%x, length %d\n", | ||
828 | netdev->name, cable_OUI, cable_len); | ||
829 | } else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN) { | ||
830 | printk(KERN_INFO "%s: unsupported cable length %d\n", | ||
831 | netdev->name, cable_len); | ||
832 | } | ||
833 | |||
834 | netxen_advert_link_change(adapter, link_status); | ||
835 | |||
836 | /* update link parameters */ | ||
837 | if (duplex == LINKEVENT_FULL_DUPLEX) | ||
838 | adapter->link_duplex = DUPLEX_FULL; | ||
839 | else | ||
840 | adapter->link_duplex = DUPLEX_HALF; | ||
841 | adapter->module_type = module; | ||
842 | adapter->link_autoneg = autoneg; | ||
843 | adapter->link_speed = link_speed; | ||
844 | } | ||
845 | |||
846 | static void | ||
847 | netxen_handle_fw_message(int desc_cnt, int index, | ||
848 | struct nx_host_sds_ring *sds_ring) | ||
849 | { | ||
850 | nx_fw_msg_t msg; | ||
851 | struct status_desc *desc; | ||
852 | int i = 0, opcode; | ||
853 | |||
854 | while (desc_cnt > 0 && i < 8) { | ||
855 | desc = &sds_ring->desc_head[index]; | ||
856 | msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]); | ||
857 | msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]); | ||
858 | |||
859 | index = get_next_index(index, sds_ring->num_desc); | ||
860 | desc_cnt--; | ||
861 | } | ||
862 | |||
863 | opcode = netxen_get_nic_msg_opcode(msg.body[0]); | ||
864 | switch (opcode) { | ||
865 | case NX_NIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE: | ||
866 | netxen_handle_linkevent(sds_ring->adapter, &msg); | ||
867 | break; | ||
868 | default: | ||
869 | break; | ||
870 | } | ||
871 | } | ||
872 | |||
801 | static int | 873 | static int |
802 | netxen_alloc_rx_skb(struct netxen_adapter *adapter, | 874 | netxen_alloc_rx_skb(struct netxen_adapter *adapter, |
803 | struct nx_host_rds_ring *rds_ring, | 875 | struct nx_host_rds_ring *rds_ring, |
@@ -916,21 +988,35 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) | |||
916 | 988 | ||
917 | int count = 0; | 989 | int count = 0; |
918 | u64 sts_data; | 990 | u64 sts_data; |
919 | int opcode, ring, index, length, cksum, pkt_offset; | 991 | int opcode, ring, index, length, cksum, pkt_offset, desc_cnt; |
920 | 992 | ||
921 | while (count < max) { | 993 | while (count < max) { |
922 | desc = &sds_ring->desc_head[consumer]; | 994 | desc = &sds_ring->desc_head[consumer]; |
923 | sts_data = le64_to_cpu(desc->status_desc_data); | 995 | sts_data = le64_to_cpu(desc->status_desc_data[0]); |
924 | 996 | ||
925 | if (!(sts_data & STATUS_OWNER_HOST)) | 997 | if (!(sts_data & STATUS_OWNER_HOST)) |
926 | break; | 998 | break; |
927 | 999 | ||
1000 | desc_cnt = netxen_get_sts_desc_cnt(sts_data); | ||
928 | ring = netxen_get_sts_type(sts_data); | 1001 | ring = netxen_get_sts_type(sts_data); |
1002 | |||
929 | if (ring > RCV_RING_JUMBO) | 1003 | if (ring > RCV_RING_JUMBO) |
930 | continue; | 1004 | goto skip; |
931 | 1005 | ||
932 | opcode = netxen_get_sts_opcode(sts_data); | 1006 | opcode = netxen_get_sts_opcode(sts_data); |
933 | 1007 | ||
1008 | switch (opcode) { | ||
1009 | case NETXEN_NIC_RXPKT_DESC: | ||
1010 | case NETXEN_OLD_RXPKT_DESC: | ||
1011 | break; | ||
1012 | case NETXEN_NIC_RESPONSE_DESC: | ||
1013 | netxen_handle_fw_message(desc_cnt, consumer, sds_ring); | ||
1014 | default: | ||
1015 | goto skip; | ||
1016 | } | ||
1017 | |||
1018 | WARN_ON(desc_cnt > 1); | ||
1019 | |||
934 | index = netxen_get_sts_refhandle(sts_data); | 1020 | index = netxen_get_sts_refhandle(sts_data); |
935 | length = netxen_get_sts_totallength(sts_data); | 1021 | length = netxen_get_sts_totallength(sts_data); |
936 | cksum = netxen_get_sts_status(sts_data); | 1022 | cksum = netxen_get_sts_status(sts_data); |
@@ -942,9 +1028,13 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max) | |||
942 | if (rxbuf) | 1028 | if (rxbuf) |
943 | list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); | 1029 | list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]); |
944 | 1030 | ||
945 | desc->status_desc_data = cpu_to_le64(STATUS_OWNER_PHANTOM); | 1031 | skip: |
946 | 1032 | for (; desc_cnt > 0; desc_cnt--) { | |
947 | consumer = get_next_index(consumer, sds_ring->num_desc); | 1033 | desc = &sds_ring->desc_head[consumer]; |
1034 | desc->status_desc_data[0] = | ||
1035 | cpu_to_le64(STATUS_OWNER_PHANTOM); | ||
1036 | consumer = get_next_index(consumer, sds_ring->num_desc); | ||
1037 | } | ||
948 | count++; | 1038 | count++; |
949 | } | 1039 | } |
950 | 1040 | ||