aboutsummaryrefslogtreecommitdiffstats
path: root/drivers
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
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')
-rw-r--r--drivers/net/netxen/netxen_nic.h108
-rw-r--r--drivers/net/netxen/netxen_nic_ethtool.c32
-rw-r--r--drivers/net/netxen/netxen_nic_hw.c22
-rw-r--r--drivers/net/netxen/netxen_nic_init.c102
-rw-r--r--drivers/net/netxen/netxen_nic_main.c55
-rw-r--r--drivers/net/netxen/netxen_nic_phan_reg.h1
6 files changed, 263 insertions, 57 deletions
diff --git a/drivers/net/netxen/netxen_nic.h b/drivers/net/netxen/netxen_nic.h
index 7e208b31a27e..f4d7e2db700b 100644
--- a/drivers/net/netxen/netxen_nic.h
+++ b/drivers/net/netxen/netxen_nic.h
@@ -354,6 +354,7 @@ struct rcv_desc {
354/* opcode field in status_desc */ 354/* opcode field in status_desc */
355#define NETXEN_NIC_RXPKT_DESC 0x04 355#define NETXEN_NIC_RXPKT_DESC 0x04
356#define NETXEN_OLD_RXPKT_DESC 0x3f 356#define NETXEN_OLD_RXPKT_DESC 0x3f
357#define NETXEN_NIC_RESPONSE_DESC 0x05
357 358
358/* for status field in status_desc */ 359/* for status field in status_desc */
359#define STATUS_NEED_CKSUM (1) 360#define STATUS_NEED_CKSUM (1)
@@ -363,8 +364,11 @@ struct rcv_desc {
363#define STATUS_OWNER_HOST (0x1ULL << 56) 364#define STATUS_OWNER_HOST (0x1ULL << 56)
364#define STATUS_OWNER_PHANTOM (0x2ULL << 56) 365#define STATUS_OWNER_PHANTOM (0x2ULL << 56)
365 366
366/* Note: sizeof(status_desc) should always be a mutliple of 2 */ 367/* Status descriptor:
367 368 0-3 port, 4-7 status, 8-11 type, 12-27 total_length
369 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset
370 53-55 desc_cnt, 56-57 owner, 58-63 opcode
371 */
368#define netxen_get_sts_port(sts_data) \ 372#define netxen_get_sts_port(sts_data) \
369 ((sts_data) & 0x0F) 373 ((sts_data) & 0x0F)
370#define netxen_get_sts_status(sts_data) \ 374#define netxen_get_sts_status(sts_data) \
@@ -379,35 +383,13 @@ struct rcv_desc {
379 (((sts_data) >> 44) & 0x0F) 383 (((sts_data) >> 44) & 0x0F)
380#define netxen_get_sts_pkt_offset(sts_data) \ 384#define netxen_get_sts_pkt_offset(sts_data) \
381 (((sts_data) >> 48) & 0x1F) 385 (((sts_data) >> 48) & 0x1F)
386#define netxen_get_sts_desc_cnt(sts_data) \
387 (((sts_data) >> 53) & 0x7)
382#define netxen_get_sts_opcode(sts_data) \ 388#define netxen_get_sts_opcode(sts_data) \
383 (((sts_data) >> 58) & 0x03F) 389 (((sts_data) >> 58) & 0x03F)
384 390
385struct status_desc { 391struct status_desc {
386 /* Bit pattern: 0-3 port, 4-7 status, 8-11 type, 12-27 total_length 392 __le64 status_desc_data[2];
387 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset
388 53-55 desc_cnt, 56-57 owner, 58-63 opcode
389 */
390 __le64 status_desc_data;
391 union {
392 struct {
393 __le32 hash_value;
394 u8 hash_type;
395 u8 msg_type;
396 u8 unused;
397 union {
398 /* Bit pattern: 0-6 lro_count indicates frag
399 * sequence, 7 last_frag indicates last frag
400 */
401 u8 lro;
402
403 /* chained buffers */
404 u8 nr_frags;
405 };
406 };
407 struct {
408 __le16 frag_handles[4];
409 };
410 };
411} __attribute__ ((aligned(16))); 393} __attribute__ ((aligned(16)));
412 394
413/* The version of the main data structure */ 395/* The version of the main data structure */
@@ -1114,6 +1096,66 @@ typedef struct {
1114#define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */ 1096#define VPORT_MISS_MODE_ACCEPT_ALL 1 /* accept all packets */
1115#define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */ 1097#define VPORT_MISS_MODE_ACCEPT_MULTI 2 /* accept unmatched multicast */
1116 1098
1099#define NX_FW_CAPABILITY_LINK_NOTIFICATION (1 << 5)
1100#define NX_FW_CAPABILITY_SWITCHING (1 << 6)
1101
1102/* module types */
1103#define LINKEVENT_MODULE_NOT_PRESENT 1
1104#define LINKEVENT_MODULE_OPTICAL_UNKNOWN 2
1105#define LINKEVENT_MODULE_OPTICAL_SRLR 3
1106#define LINKEVENT_MODULE_OPTICAL_LRM 4
1107#define LINKEVENT_MODULE_OPTICAL_SFP_1G 5
1108#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE 6
1109#define LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN 7
1110#define LINKEVENT_MODULE_TWINAX 8
1111
1112#define LINKSPEED_10GBPS 10000
1113#define LINKSPEED_1GBPS 1000
1114#define LINKSPEED_100MBPS 100
1115#define LINKSPEED_10MBPS 10
1116
1117#define LINKSPEED_ENCODED_10MBPS 0
1118#define LINKSPEED_ENCODED_100MBPS 1
1119#define LINKSPEED_ENCODED_1GBPS 2
1120
1121#define LINKEVENT_AUTONEG_DISABLED 0
1122#define LINKEVENT_AUTONEG_ENABLED 1
1123
1124#define LINKEVENT_HALF_DUPLEX 0
1125#define LINKEVENT_FULL_DUPLEX 1
1126
1127#define LINKEVENT_LINKSPEED_MBPS 0
1128#define LINKEVENT_LINKSPEED_ENCODED 1
1129
1130/* firmware response header:
1131 * 63:58 - message type
1132 * 57:56 - owner
1133 * 55:53 - desc count
1134 * 52:48 - reserved
1135 * 47:40 - completion id
1136 * 39:32 - opcode
1137 * 31:16 - error code
1138 * 15:00 - reserved
1139 */
1140#define netxen_get_nic_msgtype(msg_hdr) \
1141 ((msg_hdr >> 58) & 0x3F)
1142#define netxen_get_nic_msg_compid(msg_hdr) \
1143 ((msg_hdr >> 40) & 0xFF)
1144#define netxen_get_nic_msg_opcode(msg_hdr) \
1145 ((msg_hdr >> 32) & 0xFF)
1146#define netxen_get_nic_msg_errcode(msg_hdr) \
1147 ((msg_hdr >> 16) & 0xFFFF)
1148
1149typedef struct {
1150 union {
1151 struct {
1152 u64 hdr;
1153 u64 body[7];
1154 };
1155 u64 words[8];
1156 };
1157} nx_fw_msg_t;
1158
1117typedef struct { 1159typedef struct {
1118 __le64 qhdr; 1160 __le64 qhdr;
1119 __le64 req_hdr; 1161 __le64 req_hdr;
@@ -1177,15 +1219,21 @@ struct netxen_adapter {
1177 1219
1178 u8 mc_enabled; 1220 u8 mc_enabled;
1179 u8 max_mc_count; 1221 u8 max_mc_count;
1222 u16 resv2;
1223 u32 resv3;
1224
1225 u8 has_link_events;
1226 u8 resv1;
1180 u16 tx_context_id; 1227 u16 tx_context_id;
1181 u16 mtu; 1228 u16 mtu;
1182 u16 is_up; 1229 u16 is_up;
1230
1183 u16 link_speed; 1231 u16 link_speed;
1184 u16 link_duplex; 1232 u16 link_duplex;
1185 u16 link_autoneg; 1233 u16 link_autoneg;
1186 u16 resv1; 1234 u16 module_type;
1187 1235
1188 u32 resv2; 1236 u32 capabilities;
1189 u32 flags; 1237 u32 flags;
1190 u32 irq; 1238 u32 irq;
1191 u32 temp; 1239 u32 temp;
@@ -1398,6 +1446,8 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter);
1398int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32); 1446int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32);
1399int netxen_config_intr_coalesce(struct netxen_adapter *adapter); 1447int netxen_config_intr_coalesce(struct netxen_adapter *adapter);
1400int netxen_config_rss(struct netxen_adapter *adapter, int enable); 1448int netxen_config_rss(struct netxen_adapter *adapter, int enable);
1449int netxen_linkevent_request(struct netxen_adapter *adapter, int enable);
1450void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup);
1401 1451
1402int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu); 1452int nx_fw_cmd_set_mtu(struct netxen_adapter *adapter, int mtu);
1403int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu); 1453int netxen_nic_change_mtu(struct net_device *netdev, int new_mtu);
diff --git a/drivers/net/netxen/netxen_nic_ethtool.c b/drivers/net/netxen/netxen_nic_ethtool.c
index fe910c1715d6..5fde9e088a94 100644
--- a/drivers/net/netxen/netxen_nic_ethtool.c
+++ b/drivers/net/netxen/netxen_nic_ethtool.c
@@ -110,6 +110,7 @@ static int
110netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd) 110netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
111{ 111{
112 struct netxen_adapter *adapter = netdev_priv(dev); 112 struct netxen_adapter *adapter = netdev_priv(dev);
113 int check_sfp_module = 0;
113 114
114 /* read which mode */ 115 /* read which mode */
115 if (adapter->ahw.port_type == NETXEN_NIC_GBE) { 116 if (adapter->ahw.port_type == NETXEN_NIC_GBE) {
@@ -143,6 +144,13 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
143 ecmd->advertising = ADVERTISED_10000baseT_Full; 144 ecmd->advertising = ADVERTISED_10000baseT_Full;
144 } 145 }
145 146
147 if (netif_running(dev) && adapter->has_link_events) {
148 ecmd->speed = adapter->link_speed;
149 ecmd->autoneg = adapter->link_autoneg;
150 ecmd->duplex = adapter->link_duplex;
151 goto skip;
152 }
153
146 ecmd->port = PORT_TP; 154 ecmd->port = PORT_TP;
147 155
148 if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) { 156 if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
@@ -160,6 +168,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
160 } else 168 } else
161 return -EIO; 169 return -EIO;
162 170
171skip:
163 ecmd->phy_address = adapter->physical_port; 172 ecmd->phy_address = adapter->physical_port;
164 ecmd->transceiver = XCVR_EXTERNAL; 173 ecmd->transceiver = XCVR_EXTERNAL;
165 174
@@ -190,7 +199,7 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
190 case NETXEN_BRDTYPE_P3_HMEZ: 199 case NETXEN_BRDTYPE_P3_HMEZ:
191 ecmd->supported |= SUPPORTED_MII; 200 ecmd->supported |= SUPPORTED_MII;
192 ecmd->advertising |= ADVERTISED_MII; 201 ecmd->advertising |= ADVERTISED_MII;
193 ecmd->port = PORT_FIBRE; 202 ecmd->port = PORT_MII;
194 ecmd->autoneg = AUTONEG_DISABLE; 203 ecmd->autoneg = AUTONEG_DISABLE;
195 break; 204 break;
196 case NETXEN_BRDTYPE_P3_10G_SFP_PLUS: 205 case NETXEN_BRDTYPE_P3_10G_SFP_PLUS:
@@ -198,6 +207,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
198 case NETXEN_BRDTYPE_P3_10G_SFP_QT: 207 case NETXEN_BRDTYPE_P3_10G_SFP_QT:
199 ecmd->advertising |= ADVERTISED_TP; 208 ecmd->advertising |= ADVERTISED_TP;
200 ecmd->supported |= SUPPORTED_TP; 209 ecmd->supported |= SUPPORTED_TP;
210 check_sfp_module = netif_running(dev) &&
211 adapter->has_link_events;
201 case NETXEN_BRDTYPE_P2_SB31_10G: 212 case NETXEN_BRDTYPE_P2_SB31_10G:
202 case NETXEN_BRDTYPE_P3_10G_XFP: 213 case NETXEN_BRDTYPE_P3_10G_XFP:
203 ecmd->supported |= SUPPORTED_FIBRE; 214 ecmd->supported |= SUPPORTED_FIBRE;
@@ -212,6 +223,8 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
212 ecmd->advertising |= 223 ecmd->advertising |=
213 (ADVERTISED_FIBRE | ADVERTISED_TP); 224 (ADVERTISED_FIBRE | ADVERTISED_TP);
214 ecmd->port = PORT_FIBRE; 225 ecmd->port = PORT_FIBRE;
226 check_sfp_module = netif_running(dev) &&
227 adapter->has_link_events;
215 } else { 228 } else {
216 ecmd->autoneg = AUTONEG_ENABLE; 229 ecmd->autoneg = AUTONEG_ENABLE;
217 ecmd->supported |= (SUPPORTED_TP |SUPPORTED_Autoneg); 230 ecmd->supported |= (SUPPORTED_TP |SUPPORTED_Autoneg);
@@ -226,6 +239,23 @@ netxen_nic_get_settings(struct net_device *dev, struct ethtool_cmd *ecmd)
226 return -EIO; 239 return -EIO;
227 } 240 }
228 241
242 if (check_sfp_module) {
243 switch (adapter->module_type) {
244 case LINKEVENT_MODULE_OPTICAL_UNKNOWN:
245 case LINKEVENT_MODULE_OPTICAL_SRLR:
246 case LINKEVENT_MODULE_OPTICAL_LRM:
247 case LINKEVENT_MODULE_OPTICAL_SFP_1G:
248 ecmd->port = PORT_FIBRE;
249 break;
250 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE:
251 case LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN:
252 case LINKEVENT_MODULE_TWINAX:
253 ecmd->port = PORT_TP;
254 default:
255 ecmd->port = -1;
256 }
257 }
258
229 return 0; 259 return 0;
230} 260}
231 261
diff --git a/drivers/net/netxen/netxen_nic_hw.c b/drivers/net/netxen/netxen_nic_hw.c
index 8416962cc9ac..33444a20e4f7 100644
--- a/drivers/net/netxen/netxen_nic_hw.c
+++ b/drivers/net/netxen/netxen_nic_hw.c
@@ -731,6 +731,28 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable)
731 return rv; 731 return rv;
732} 732}
733 733
734int netxen_linkevent_request(struct netxen_adapter *adapter, int enable)
735{
736 nx_nic_req_t req;
737 u64 word;
738 int rv;
739
740 memset(&req, 0, sizeof(nx_nic_req_t));
741 req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);
742
743 word = NX_NIC_H2C_OPCODE_GET_LINKEVENT | ((u64)adapter->portnum << 16);
744 req.req_hdr = cpu_to_le64(word);
745 req.words[0] = cpu_to_le64(enable);
746
747 rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
748 if (rv != 0) {
749 printk(KERN_ERR "%s: could not configure link notification\n",
750 adapter->netdev->name);
751 }
752
753 return rv;
754}
755
734/* 756/*
735 * netxen_nic_change_mtu - Change the Maximum Transfer Unit 757 * netxen_nic_change_mtu - Change the Maximum Transfer Unit
736 * @returns 0 on success, negative on failure 758 * @returns 0 on success, negative on failure
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
diff --git a/drivers/net/netxen/netxen_nic_main.c b/drivers/net/netxen/netxen_nic_main.c
index 665fce561d4a..bd93296be4dd 100644
--- a/drivers/net/netxen/netxen_nic_main.c
+++ b/drivers/net/netxen/netxen_nic_main.c
@@ -787,6 +787,9 @@ netxen_nic_up(struct netxen_adapter *adapter, struct net_device *netdev)
787 if (adapter->max_sds_rings > 1) 787 if (adapter->max_sds_rings > 1)
788 netxen_config_rss(adapter, 1); 788 netxen_config_rss(adapter, 1);
789 789
790 if (NX_IS_REVISION_P3(adapter->ahw.revision_id))
791 netxen_linkevent_request(adapter, 1);
792
790 return 0; 793 return 0;
791} 794}
792 795
@@ -1493,26 +1496,9 @@ static int netxen_nic_check_temp(struct netxen_adapter *adapter)
1493 return rv; 1496 return rv;
1494} 1497}
1495 1498
1496static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter) 1499void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup)
1497{ 1500{
1498 struct net_device *netdev = adapter->netdev; 1501 struct net_device *netdev = adapter->netdev;
1499 u32 val, port, linkup;
1500
1501 port = adapter->physical_port;
1502
1503 if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
1504 val = adapter->pci_read_normalize(adapter, CRB_XG_STATE_P3);
1505 val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val);
1506 linkup = (val == XG_LINK_UP_P3);
1507 } else {
1508 val = adapter->pci_read_normalize(adapter, CRB_XG_STATE);
1509 if (adapter->ahw.port_type == NETXEN_NIC_GBE)
1510 linkup = (val >> port) & 1;
1511 else {
1512 val = (val >> port*8) & 0xff;
1513 linkup = (val == XG_LINK_UP);
1514 }
1515 }
1516 1502
1517 if (adapter->ahw.linkup && !linkup) { 1503 if (adapter->ahw.linkup && !linkup) {
1518 printk(KERN_INFO "%s: %s NIC Link is down\n", 1504 printk(KERN_INFO "%s: %s NIC Link is down\n",
@@ -1523,7 +1509,9 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter)
1523 netif_stop_queue(netdev); 1509 netif_stop_queue(netdev);
1524 } 1510 }
1525 1511
1526 netxen_nic_set_link_parameters(adapter); 1512 if (!adapter->has_link_events)
1513 netxen_nic_set_link_parameters(adapter);
1514
1527 } else if (!adapter->ahw.linkup && linkup) { 1515 } else if (!adapter->ahw.linkup && linkup) {
1528 printk(KERN_INFO "%s: %s NIC Link is up\n", 1516 printk(KERN_INFO "%s: %s NIC Link is up\n",
1529 netxen_nic_driver_name, netdev->name); 1517 netxen_nic_driver_name, netdev->name);
@@ -1533,10 +1521,34 @@ static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter)
1533 netif_wake_queue(netdev); 1521 netif_wake_queue(netdev);
1534 } 1522 }
1535 1523
1536 netxen_nic_set_link_parameters(adapter); 1524 if (!adapter->has_link_events)
1525 netxen_nic_set_link_parameters(adapter);
1537 } 1526 }
1538} 1527}
1539 1528
1529static void netxen_nic_handle_phy_intr(struct netxen_adapter *adapter)
1530{
1531 u32 val, port, linkup;
1532
1533 port = adapter->physical_port;
1534
1535 if (NX_IS_REVISION_P3(adapter->ahw.revision_id)) {
1536 val = adapter->pci_read_normalize(adapter, CRB_XG_STATE_P3);
1537 val = XG_LINK_STATE_P3(adapter->ahw.pci_func, val);
1538 linkup = (val == XG_LINK_UP_P3);
1539 } else {
1540 val = adapter->pci_read_normalize(adapter, CRB_XG_STATE);
1541 if (adapter->ahw.port_type == NETXEN_NIC_GBE)
1542 linkup = (val >> port) & 1;
1543 else {
1544 val = (val >> port*8) & 0xff;
1545 linkup = (val == XG_LINK_UP);
1546 }
1547 }
1548
1549 netxen_advert_link_change(adapter, linkup);
1550}
1551
1540static void netxen_watchdog(unsigned long v) 1552static void netxen_watchdog(unsigned long v)
1541{ 1553{
1542 struct netxen_adapter *adapter = (struct netxen_adapter *)v; 1554 struct netxen_adapter *adapter = (struct netxen_adapter *)v;
@@ -1552,7 +1564,8 @@ void netxen_watchdog_task(struct work_struct *work)
1552 if ((adapter->portnum == 0) && netxen_nic_check_temp(adapter)) 1564 if ((adapter->portnum == 0) && netxen_nic_check_temp(adapter))
1553 return; 1565 return;
1554 1566
1555 netxen_nic_handle_phy_intr(adapter); 1567 if (!adapter->has_link_events)
1568 netxen_nic_handle_phy_intr(adapter);
1556 1569
1557 if (netif_running(adapter->netdev)) 1570 if (netif_running(adapter->netdev))
1558 mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ); 1571 mod_timer(&adapter->watchdog_timer, jiffies + 2 * HZ);
diff --git a/drivers/net/netxen/netxen_nic_phan_reg.h b/drivers/net/netxen/netxen_nic_phan_reg.h
index 18ea35d51160..ecd622ead0e9 100644
--- a/drivers/net/netxen/netxen_nic_phan_reg.h
+++ b/drivers/net/netxen/netxen_nic_phan_reg.h
@@ -134,6 +134,7 @@
134#define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc) 134#define CRB_NIC_CAPABILITIES_FW NETXEN_NIC_REG(0x1dc)
135#define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270) 135#define CRB_NIC_MSI_MODE_HOST NETXEN_NIC_REG(0x270)
136#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274) 136#define CRB_NIC_MSI_MODE_FW NETXEN_NIC_REG(0x274)
137#define CRB_FW_CAPABILITIES_1 NETXEN_NIC_REG(0x128)
137 138
138#define INTR_SCHEME_PERPORT 0x1 139#define INTR_SCHEME_PERPORT 0x1
139#define MSI_MODE_MULTIFUNC 0x1 140#define MSI_MODE_MULTIFUNC 0x1