diff options
author | Sathya Perla <sathyap@serverengines.com> | 2009-06-17 20:10:27 -0400 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2009-06-19 03:18:42 -0400 |
commit | a8f447bda3ee00e3a3ab080c48db40078ea65221 (patch) | |
tree | 7b164e3dd0dee5da5229462c668c98a6297517a3 /drivers/net | |
parent | 24307eef74bd38e3fc6a6df8f8a1bfc48967f9f6 (diff) |
be2net: receive asynchronous link status notifications from BE
Rcv and process ansync link status notifications from BE instead of polling
for link status in the be_worker thread.
Signed-off-by: Sathya Perla <sathyap@serverengines.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r-- | drivers/net/benet/be.h | 6 | ||||
-rw-r--r-- | drivers/net/benet/be_cmds.c | 34 | ||||
-rw-r--r-- | drivers/net/benet/be_cmds.h | 36 | ||||
-rw-r--r-- | drivers/net/benet/be_main.c | 37 |
4 files changed, 80 insertions, 33 deletions
diff --git a/drivers/net/benet/be.h b/drivers/net/benet/be.h index 94b75cb072f7..f703758f0a6e 100644 --- a/drivers/net/benet/be.h +++ b/drivers/net/benet/be.h | |||
@@ -163,6 +163,10 @@ struct be_ctrl_info { | |||
163 | struct be_mcc_obj mcc_obj; | 163 | struct be_mcc_obj mcc_obj; |
164 | spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ | 164 | spinlock_t mcc_lock; /* For serializing mcc cmds to BE card */ |
165 | spinlock_t mcc_cq_lock; | 165 | spinlock_t mcc_cq_lock; |
166 | |||
167 | /* MCC Async callback */ | ||
168 | void (*async_cb)(void *adapter, bool link_up); | ||
169 | void *adapter_ctxt; | ||
166 | }; | 170 | }; |
167 | 171 | ||
168 | #include "be_cmds.h" | 172 | #include "be_cmds.h" |
@@ -272,7 +276,7 @@ struct be_adapter { | |||
272 | u32 if_handle; /* Used to configure filtering */ | 276 | u32 if_handle; /* Used to configure filtering */ |
273 | u32 pmac_id; /* MAC addr handle used by BE card */ | 277 | u32 pmac_id; /* MAC addr handle used by BE card */ |
274 | 278 | ||
275 | struct be_link_info link; | 279 | bool link_up; |
276 | u32 port_num; | 280 | u32 port_num; |
277 | bool promiscuous; | 281 | bool promiscuous; |
278 | }; | 282 | }; |
diff --git a/drivers/net/benet/be_cmds.c b/drivers/net/benet/be_cmds.c index 4a2e1f518f78..583517ed56f0 100644 --- a/drivers/net/benet/be_cmds.c +++ b/drivers/net/benet/be_cmds.c | |||
@@ -69,6 +69,20 @@ static int be_mcc_compl_process(struct be_ctrl_info *ctrl, | |||
69 | return 0; | 69 | return 0; |
70 | } | 70 | } |
71 | 71 | ||
72 | /* Link state evt is a string of bytes; no need for endian swapping */ | ||
73 | static void be_async_link_state_process(struct be_ctrl_info *ctrl, | ||
74 | struct be_async_event_link_state *evt) | ||
75 | { | ||
76 | ctrl->async_cb(ctrl->adapter_ctxt, | ||
77 | evt->port_link_status == ASYNC_EVENT_LINK_UP ? true : false); | ||
78 | } | ||
79 | |||
80 | static inline bool is_link_state_evt(u32 trailer) | ||
81 | { | ||
82 | return (((trailer >> ASYNC_TRAILER_EVENT_CODE_SHIFT) & | ||
83 | ASYNC_TRAILER_EVENT_CODE_MASK) == | ||
84 | ASYNC_EVENT_CODE_LINK_STATE); | ||
85 | } | ||
72 | 86 | ||
73 | static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_ctrl_info *ctrl) | 87 | static struct be_mcc_cq_entry *be_mcc_compl_get(struct be_ctrl_info *ctrl) |
74 | { | 88 | { |
@@ -89,7 +103,14 @@ void be_process_mcc(struct be_ctrl_info *ctrl) | |||
89 | 103 | ||
90 | spin_lock_bh(&ctrl->mcc_cq_lock); | 104 | spin_lock_bh(&ctrl->mcc_cq_lock); |
91 | while ((compl = be_mcc_compl_get(ctrl))) { | 105 | while ((compl = be_mcc_compl_get(ctrl))) { |
92 | if (!(compl->flags & CQE_FLAGS_ASYNC_MASK)) { | 106 | if (compl->flags & CQE_FLAGS_ASYNC_MASK) { |
107 | /* Interpret flags as an async trailer */ | ||
108 | BUG_ON(!is_link_state_evt(compl->flags)); | ||
109 | |||
110 | /* Interpret compl as a async link evt */ | ||
111 | be_async_link_state_process(ctrl, | ||
112 | (struct be_async_event_link_state *) compl); | ||
113 | } else { | ||
93 | be_mcc_compl_process(ctrl, compl); | 114 | be_mcc_compl_process(ctrl, compl); |
94 | atomic_dec(&ctrl->mcc_obj.q.used); | 115 | atomic_dec(&ctrl->mcc_obj.q.used); |
95 | } | 116 | } |
@@ -786,13 +807,15 @@ int be_cmd_get_stats(struct be_ctrl_info *ctrl, struct be_dma_mem *nonemb_cmd) | |||
786 | } | 807 | } |
787 | 808 | ||
788 | int be_cmd_link_status_query(struct be_ctrl_info *ctrl, | 809 | int be_cmd_link_status_query(struct be_ctrl_info *ctrl, |
789 | struct be_link_info *link) | 810 | bool *link_up) |
790 | { | 811 | { |
791 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); | 812 | struct be_mcc_wrb *wrb = wrb_from_mbox(&ctrl->mbox_mem); |
792 | struct be_cmd_req_link_status *req = embedded_payload(wrb); | 813 | struct be_cmd_req_link_status *req = embedded_payload(wrb); |
793 | int status; | 814 | int status; |
794 | 815 | ||
795 | spin_lock(&ctrl->mbox_lock); | 816 | spin_lock(&ctrl->mbox_lock); |
817 | |||
818 | *link_up = false; | ||
796 | memset(wrb, 0, sizeof(*wrb)); | 819 | memset(wrb, 0, sizeof(*wrb)); |
797 | 820 | ||
798 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); | 821 | be_wrb_hdr_prepare(wrb, sizeof(*req), true, 0); |
@@ -803,11 +826,8 @@ int be_cmd_link_status_query(struct be_ctrl_info *ctrl, | |||
803 | status = be_mbox_db_ring(ctrl); | 826 | status = be_mbox_db_ring(ctrl); |
804 | if (!status) { | 827 | if (!status) { |
805 | struct be_cmd_resp_link_status *resp = embedded_payload(wrb); | 828 | struct be_cmd_resp_link_status *resp = embedded_payload(wrb); |
806 | link->speed = resp->mac_speed; | 829 | if (resp->mac_speed != PHY_LINK_SPEED_ZERO) |
807 | link->duplex = resp->mac_duplex; | 830 | *link_up = true; |
808 | link->fault = resp->mac_fault; | ||
809 | } else { | ||
810 | link->speed = PHY_LINK_SPEED_ZERO; | ||
811 | } | 831 | } |
812 | 832 | ||
813 | spin_unlock(&ctrl->mbox_lock); | 833 | spin_unlock(&ctrl->mbox_lock); |
diff --git a/drivers/net/benet/be_cmds.h b/drivers/net/benet/be_cmds.h index a567aa437ec9..747626da7b4e 100644 --- a/drivers/net/benet/be_cmds.h +++ b/drivers/net/benet/be_cmds.h | |||
@@ -76,6 +76,34 @@ struct be_mcc_cq_entry { | |||
76 | u32 flags; /* dword 3 */ | 76 | u32 flags; /* dword 3 */ |
77 | }; | 77 | }; |
78 | 78 | ||
79 | /* When the async bit of mcc_compl is set, the last 4 bytes of | ||
80 | * mcc_compl is interpreted as follows: | ||
81 | */ | ||
82 | #define ASYNC_TRAILER_EVENT_CODE_SHIFT 8 /* bits 8 - 15 */ | ||
83 | #define ASYNC_TRAILER_EVENT_CODE_MASK 0xFF | ||
84 | #define ASYNC_EVENT_CODE_LINK_STATE 0x1 | ||
85 | struct be_async_event_trailer { | ||
86 | u32 code; | ||
87 | }; | ||
88 | |||
89 | enum { | ||
90 | ASYNC_EVENT_LINK_DOWN = 0x0, | ||
91 | ASYNC_EVENT_LINK_UP = 0x1 | ||
92 | }; | ||
93 | |||
94 | /* When the event code of an async trailer is link-state, the mcc_compl | ||
95 | * must be interpreted as follows | ||
96 | */ | ||
97 | struct be_async_event_link_state { | ||
98 | u8 physical_port; | ||
99 | u8 port_link_status; | ||
100 | u8 port_duplex; | ||
101 | u8 port_speed; | ||
102 | u8 port_fault; | ||
103 | u8 rsvd0[7]; | ||
104 | struct be_async_event_trailer trailer; | ||
105 | } __packed; | ||
106 | |||
79 | struct be_mcc_mailbox { | 107 | struct be_mcc_mailbox { |
80 | struct be_mcc_wrb wrb; | 108 | struct be_mcc_wrb wrb; |
81 | struct be_mcc_cq_entry cqe; | 109 | struct be_mcc_cq_entry cqe; |
@@ -580,12 +608,6 @@ struct be_cmd_req_link_status { | |||
580 | u32 rsvd; | 608 | u32 rsvd; |
581 | }; | 609 | }; |
582 | 610 | ||
583 | struct be_link_info { | ||
584 | u8 duplex; | ||
585 | u8 speed; | ||
586 | u8 fault; | ||
587 | }; | ||
588 | |||
589 | enum { | 611 | enum { |
590 | PHY_LINK_DUPLEX_NONE = 0x0, | 612 | PHY_LINK_DUPLEX_NONE = 0x0, |
591 | PHY_LINK_DUPLEX_HALF = 0x1, | 613 | PHY_LINK_DUPLEX_HALF = 0x1, |
@@ -704,7 +726,7 @@ extern int be_cmd_rxq_create(struct be_ctrl_info *ctrl, | |||
704 | extern int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, | 726 | extern int be_cmd_q_destroy(struct be_ctrl_info *ctrl, struct be_queue_info *q, |
705 | int type); | 727 | int type); |
706 | extern int be_cmd_link_status_query(struct be_ctrl_info *ctrl, | 728 | extern int be_cmd_link_status_query(struct be_ctrl_info *ctrl, |
707 | struct be_link_info *link); | 729 | bool *link_up); |
708 | extern int be_cmd_reset(struct be_ctrl_info *ctrl); | 730 | extern int be_cmd_reset(struct be_ctrl_info *ctrl); |
709 | extern int be_cmd_get_stats(struct be_ctrl_info *ctrl, | 731 | extern int be_cmd_get_stats(struct be_ctrl_info *ctrl, |
710 | struct be_dma_mem *nonemb_cmd); | 732 | struct be_dma_mem *nonemb_cmd); |
diff --git a/drivers/net/benet/be_main.c b/drivers/net/benet/be_main.c index 3dc68034c21d..66c10c87f517 100644 --- a/drivers/net/benet/be_main.c +++ b/drivers/net/benet/be_main.c | |||
@@ -214,28 +214,24 @@ static void netdev_stats_update(struct be_adapter *adapter) | |||
214 | dev_stats->tx_window_errors = 0; | 214 | dev_stats->tx_window_errors = 0; |
215 | } | 215 | } |
216 | 216 | ||
217 | static void be_link_status_update(struct be_adapter *adapter) | 217 | void be_link_status_update(void *ctxt, bool link_up) |
218 | { | 218 | { |
219 | struct be_link_info *prev = &adapter->link; | 219 | struct be_adapter *adapter = ctxt; |
220 | struct be_link_info now = { 0 }; | ||
221 | struct net_device *netdev = adapter->netdev; | 220 | struct net_device *netdev = adapter->netdev; |
222 | 221 | ||
223 | be_cmd_link_status_query(&adapter->ctrl, &now); | ||
224 | |||
225 | /* If link came up or went down */ | 222 | /* If link came up or went down */ |
226 | if (now.speed != prev->speed && (now.speed == PHY_LINK_SPEED_ZERO || | 223 | if (adapter->link_up != link_up) { |
227 | prev->speed == PHY_LINK_SPEED_ZERO)) { | 224 | if (link_up) { |
228 | if (now.speed == PHY_LINK_SPEED_ZERO) { | ||
229 | netif_stop_queue(netdev); | ||
230 | netif_carrier_off(netdev); | ||
231 | printk(KERN_INFO "%s: Link down\n", netdev->name); | ||
232 | } else { | ||
233 | netif_start_queue(netdev); | 225 | netif_start_queue(netdev); |
234 | netif_carrier_on(netdev); | 226 | netif_carrier_on(netdev); |
235 | printk(KERN_INFO "%s: Link up\n", netdev->name); | 227 | printk(KERN_INFO "%s: Link up\n", netdev->name); |
228 | } else { | ||
229 | netif_stop_queue(netdev); | ||
230 | netif_carrier_off(netdev); | ||
231 | printk(KERN_INFO "%s: Link down\n", netdev->name); | ||
236 | } | 232 | } |
233 | adapter->link_up = link_up; | ||
237 | } | 234 | } |
238 | *prev = now; | ||
239 | } | 235 | } |
240 | 236 | ||
241 | /* Update the EQ delay n BE based on the RX frags consumed / sec */ | 237 | /* Update the EQ delay n BE based on the RX frags consumed / sec */ |
@@ -1395,9 +1391,6 @@ static void be_worker(struct work_struct *work) | |||
1395 | container_of(work, struct be_adapter, work.work); | 1391 | container_of(work, struct be_adapter, work.work); |
1396 | int status; | 1392 | int status; |
1397 | 1393 | ||
1398 | /* Check link */ | ||
1399 | be_link_status_update(adapter); | ||
1400 | |||
1401 | /* Get Stats */ | 1394 | /* Get Stats */ |
1402 | status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd); | 1395 | status = be_cmd_get_stats(&adapter->ctrl, &adapter->stats.cmd); |
1403 | if (!status) | 1396 | if (!status) |
@@ -1522,6 +1515,8 @@ static int be_open(struct net_device *netdev) | |||
1522 | struct be_ctrl_info *ctrl = &adapter->ctrl; | 1515 | struct be_ctrl_info *ctrl = &adapter->ctrl; |
1523 | struct be_eq_obj *rx_eq = &adapter->rx_eq; | 1516 | struct be_eq_obj *rx_eq = &adapter->rx_eq; |
1524 | struct be_eq_obj *tx_eq = &adapter->tx_eq; | 1517 | struct be_eq_obj *tx_eq = &adapter->tx_eq; |
1518 | bool link_up; | ||
1519 | int status; | ||
1525 | 1520 | ||
1526 | /* First time posting */ | 1521 | /* First time posting */ |
1527 | be_post_rx_frags(adapter); | 1522 | be_post_rx_frags(adapter); |
@@ -1540,7 +1535,10 @@ static int be_open(struct net_device *netdev) | |||
1540 | /* Rx compl queue may be in unarmed state; rearm it */ | 1535 | /* Rx compl queue may be in unarmed state; rearm it */ |
1541 | be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0); | 1536 | be_cq_notify(ctrl, adapter->rx_obj.cq.id, true, 0); |
1542 | 1537 | ||
1543 | be_link_status_update(adapter); | 1538 | status = be_cmd_link_status_query(ctrl, &link_up); |
1539 | if (status) | ||
1540 | return status; | ||
1541 | be_link_status_update(adapter, link_up); | ||
1544 | 1542 | ||
1545 | schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); | 1543 | schedule_delayed_work(&adapter->work, msecs_to_jiffies(100)); |
1546 | return 0; | 1544 | return 0; |
@@ -1617,7 +1615,7 @@ static int be_close(struct net_device *netdev) | |||
1617 | 1615 | ||
1618 | netif_stop_queue(netdev); | 1616 | netif_stop_queue(netdev); |
1619 | netif_carrier_off(netdev); | 1617 | netif_carrier_off(netdev); |
1620 | adapter->link.speed = PHY_LINK_SPEED_ZERO; | 1618 | adapter->link_up = false; |
1621 | 1619 | ||
1622 | be_intr_set(ctrl, false); | 1620 | be_intr_set(ctrl, false); |
1623 | 1621 | ||
@@ -1808,6 +1806,9 @@ static int be_ctrl_init(struct be_adapter *adapter) | |||
1808 | spin_lock_init(&ctrl->mcc_lock); | 1806 | spin_lock_init(&ctrl->mcc_lock); |
1809 | spin_lock_init(&ctrl->mcc_cq_lock); | 1807 | spin_lock_init(&ctrl->mcc_cq_lock); |
1810 | 1808 | ||
1809 | ctrl->async_cb = be_link_status_update; | ||
1810 | ctrl->adapter_ctxt = adapter; | ||
1811 | |||
1811 | val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); | 1812 | val = ioread32(ctrl->pcicfg + PCICFG_MEMBAR_CTRL_INT_CTRL_OFFSET); |
1812 | ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & | 1813 | ctrl->pci_func = (val >> MEMBAR_CTRL_INT_CTRL_PFUNC_SHIFT) & |
1813 | MEMBAR_CTRL_INT_CTRL_PFUNC_MASK; | 1814 | MEMBAR_CTRL_INT_CTRL_PFUNC_MASK; |