aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/netxen/netxen_nic_init.c
diff options
context:
space:
mode:
authorDhananjay Phadke <dhananjay@netxen.com>2009-04-07 18:50:42 -0400
committerDavid S. Miller <davem@davemloft.net>2009-04-08 18:58:27 -0400
commit3bf26ce3f4cc3c9e0d0478b4016c6113a16faaf1 (patch)
tree8478804493b6e749a6e61870c8c3b5b9549469ad /drivers/net/netxen/netxen_nic_init.c
parent56a007871a6689db80e19f63fe6dc3692daa2a6f (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.c102
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
806static void
807netxen_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
846static void
847netxen_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
801static int 873static int
802netxen_alloc_rx_skb(struct netxen_adapter *adapter, 874netxen_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); 1031skip:
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