diff options
author | John Fastabend <john.r.fastabend@intel.com> | 2011-02-10 09:40:01 -0500 |
---|---|---|
committer | Jeff Kirsher <jeffrey.t.kirsher@intel.com> | 2011-02-11 11:47:15 -0500 |
commit | d033d526a465c4bb8a499a0b5df65b3e7cf4da6f (patch) | |
tree | 570fba34e3fe39dd158dbf38296ca486298b2548 | |
parent | 55320cb58baebd1795ec92f4550a1e8b38bf9ddf (diff) |
ixgbe: DCB, implement 802.1Qaz routines
Implements 802.1Qaz support for ixgbe driver. Additionally,
this adds IEEE_8021QAZ_TSA_{} defines to dcbnl.h this is to
avoid having to use cryptic numeric codes for the TSA type.
Signed-off-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Ross Brattain <ross.b.brattain@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
-rw-r--r-- | drivers/net/ixgbe/ixgbe.h | 4 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_dcb.c | 103 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_dcb.h | 4 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_dcb_82598.c | 2 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_dcb_nl.c | 91 | ||||
-rw-r--r-- | drivers/net/ixgbe/ixgbe_main.c | 4 | ||||
-rw-r--r-- | include/linux/dcbnl.h | 5 |
7 files changed, 212 insertions, 1 deletions
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h index 3b8c92463617..d04afdeee035 100644 --- a/drivers/net/ixgbe/ixgbe.h +++ b/drivers/net/ixgbe/ixgbe.h | |||
@@ -334,6 +334,10 @@ struct ixgbe_adapter { | |||
334 | u16 bd_number; | 334 | u16 bd_number; |
335 | struct work_struct reset_task; | 335 | struct work_struct reset_task; |
336 | struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; | 336 | struct ixgbe_q_vector *q_vector[MAX_MSIX_Q_VECTORS]; |
337 | |||
338 | /* DCB parameters */ | ||
339 | struct ieee_pfc *ixgbe_ieee_pfc; | ||
340 | struct ieee_ets *ixgbe_ieee_ets; | ||
337 | struct ixgbe_dcb_config dcb_cfg; | 341 | struct ixgbe_dcb_config dcb_cfg; |
338 | struct ixgbe_dcb_config temp_dcb_cfg; | 342 | struct ixgbe_dcb_config temp_dcb_cfg; |
339 | u8 dcb_set_bitmap; | 343 | u8 dcb_set_bitmap; |
diff --git a/drivers/net/ixgbe/ixgbe_dcb.c b/drivers/net/ixgbe/ixgbe_dcb.c index d9bb670ae258..13c962efbfc9 100644 --- a/drivers/net/ixgbe/ixgbe_dcb.c +++ b/drivers/net/ixgbe/ixgbe_dcb.c | |||
@@ -34,6 +34,42 @@ | |||
34 | #include "ixgbe_dcb_82599.h" | 34 | #include "ixgbe_dcb_82599.h" |
35 | 35 | ||
36 | /** | 36 | /** |
37 | * ixgbe_ieee_credits - This calculates the ieee traffic class | ||
38 | * credits from the configured bandwidth percentages. Credits | ||
39 | * are the smallest unit programable into the underlying | ||
40 | * hardware. The IEEE 802.1Qaz specification do not use bandwidth | ||
41 | * groups so this is much simplified from the CEE case. | ||
42 | */ | ||
43 | s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame) | ||
44 | { | ||
45 | int min_percent = 100; | ||
46 | int min_credit, multiplier; | ||
47 | int i; | ||
48 | |||
49 | min_credit = ((max_frame / 2) + DCB_CREDIT_QUANTUM - 1) / | ||
50 | DCB_CREDIT_QUANTUM; | ||
51 | |||
52 | for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { | ||
53 | if (bw[i] < min_percent && bw[i]) | ||
54 | min_percent = bw[i]; | ||
55 | } | ||
56 | |||
57 | multiplier = (min_credit / min_percent) + 1; | ||
58 | |||
59 | /* Find out the hw credits for each TC */ | ||
60 | for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { | ||
61 | int val = min(bw[i] * multiplier, MAX_CREDIT_REFILL); | ||
62 | |||
63 | if (val < min_credit) | ||
64 | val = min_credit; | ||
65 | refill[i] = val; | ||
66 | |||
67 | max[i] = (bw[i] * MAX_CREDIT)/100; | ||
68 | } | ||
69 | return 0; | ||
70 | } | ||
71 | |||
72 | /** | ||
37 | * ixgbe_dcb_calculate_tc_credits - Calculates traffic class credits | 73 | * ixgbe_dcb_calculate_tc_credits - Calculates traffic class credits |
38 | * @ixgbe_dcb_config: Struct containing DCB settings. | 74 | * @ixgbe_dcb_config: Struct containing DCB settings. |
39 | * @direction: Configuring either Tx or Rx. | 75 | * @direction: Configuring either Tx or Rx. |
@@ -236,3 +272,70 @@ s32 ixgbe_dcb_hw_config(struct ixgbe_hw *hw, | |||
236 | return ret; | 272 | return ret; |
237 | } | 273 | } |
238 | 274 | ||
275 | /* Helper routines to abstract HW specifics from DCB netlink ops */ | ||
276 | s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en) | ||
277 | { | ||
278 | int ret = -EINVAL; | ||
279 | |||
280 | switch (hw->mac.type) { | ||
281 | case ixgbe_mac_82598EB: | ||
282 | ret = ixgbe_dcb_config_pfc_82598(hw, pfc_en); | ||
283 | break; | ||
284 | case ixgbe_mac_82599EB: | ||
285 | case ixgbe_mac_X540: | ||
286 | ret = ixgbe_dcb_config_pfc_82599(hw, pfc_en); | ||
287 | break; | ||
288 | default: | ||
289 | break; | ||
290 | } | ||
291 | return ret; | ||
292 | } | ||
293 | |||
294 | s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw, | ||
295 | u16 *refill, u16 *max, u8 *bwg_id, u8 *tsa) | ||
296 | { | ||
297 | int i; | ||
298 | u8 prio_type[IEEE_8021QAZ_MAX_TCS]; | ||
299 | |||
300 | /* Map TSA onto CEE prio type */ | ||
301 | for (i = 0; i < IEEE_8021QAZ_MAX_TCS; i++) { | ||
302 | switch (tsa[i]) { | ||
303 | case IEEE_8021QAZ_TSA_STRICT: | ||
304 | prio_type[i] = 2; | ||
305 | break; | ||
306 | case IEEE_8021QAZ_TSA_ETS: | ||
307 | prio_type[i] = 0; | ||
308 | break; | ||
309 | default: | ||
310 | /* Hardware only supports priority strict or | ||
311 | * ETS transmission selection algorithms if | ||
312 | * we receive some other value from dcbnl | ||
313 | * throw an error | ||
314 | */ | ||
315 | return -EINVAL; | ||
316 | } | ||
317 | } | ||
318 | |||
319 | switch (hw->mac.type) { | ||
320 | case ixgbe_mac_82598EB: | ||
321 | ixgbe_dcb_config_rx_arbiter_82598(hw, refill, max, | ||
322 | prio_type); | ||
323 | ixgbe_dcb_config_tx_desc_arbiter_82598(hw, refill, max, | ||
324 | bwg_id, prio_type); | ||
325 | ixgbe_dcb_config_tx_data_arbiter_82598(hw, refill, max, | ||
326 | bwg_id, prio_type); | ||
327 | break; | ||
328 | case ixgbe_mac_82599EB: | ||
329 | case ixgbe_mac_X540: | ||
330 | ixgbe_dcb_config_rx_arbiter_82599(hw, refill, max, | ||
331 | bwg_id, prio_type); | ||
332 | ixgbe_dcb_config_tx_desc_arbiter_82599(hw, refill, max, | ||
333 | bwg_id, prio_type); | ||
334 | ixgbe_dcb_config_tx_data_arbiter_82599(hw, refill, max, | ||
335 | bwg_id, prio_type); | ||
336 | break; | ||
337 | default: | ||
338 | break; | ||
339 | } | ||
340 | return 0; | ||
341 | } | ||
diff --git a/drivers/net/ixgbe/ixgbe_dcb.h b/drivers/net/ixgbe/ixgbe_dcb.h index aa6cb5f9ebf4..4e4a641f3d53 100644 --- a/drivers/net/ixgbe/ixgbe_dcb.h +++ b/drivers/net/ixgbe/ixgbe_dcb.h | |||
@@ -150,10 +150,14 @@ struct ixgbe_dcb_config { | |||
150 | void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en); | 150 | void ixgbe_dcb_unpack_pfc(struct ixgbe_dcb_config *cfg, u8 *pfc_en); |
151 | 151 | ||
152 | /* DCB credits calculation */ | 152 | /* DCB credits calculation */ |
153 | s32 ixgbe_ieee_credits(__u8 *bw, __u16 *refill, __u16 *max, int max_frame); | ||
153 | s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *, | 154 | s32 ixgbe_dcb_calculate_tc_credits(struct ixgbe_hw *, |
154 | struct ixgbe_dcb_config *, int, u8); | 155 | struct ixgbe_dcb_config *, int, u8); |
155 | 156 | ||
156 | /* DCB hw initialization */ | 157 | /* DCB hw initialization */ |
158 | s32 ixgbe_dcb_hw_ets_config(struct ixgbe_hw *hw, | ||
159 | u16 *refill, u16 *max, u8 *bwg_id, u8 *prio_type); | ||
160 | s32 ixgbe_dcb_hw_pfc_config(struct ixgbe_hw *hw, u8 pfc_en); | ||
157 | s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *); | 161 | s32 ixgbe_dcb_hw_config(struct ixgbe_hw *, struct ixgbe_dcb_config *); |
158 | 162 | ||
159 | /* DCB definitions for credit calculation */ | 163 | /* DCB definitions for credit calculation */ |
diff --git a/drivers/net/ixgbe/ixgbe_dcb_82598.c b/drivers/net/ixgbe/ixgbe_dcb_82598.c index d1288060cbd0..2965edcdac7b 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_82598.c +++ b/drivers/net/ixgbe/ixgbe_dcb_82598.c | |||
@@ -291,7 +291,7 @@ out: | |||
291 | * Configure queue statistics registers, all queues belonging to same traffic | 291 | * Configure queue statistics registers, all queues belonging to same traffic |
292 | * class uses a single set of queue statistics counters. | 292 | * class uses a single set of queue statistics counters. |
293 | */ | 293 | */ |
294 | static s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) | 294 | s32 ixgbe_dcb_config_tc_stats_82598(struct ixgbe_hw *hw) |
295 | { | 295 | { |
296 | u32 reg = 0; | 296 | u32 reg = 0; |
297 | u8 i = 0; | 297 | u8 i = 0; |
diff --git a/drivers/net/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ixgbe/ixgbe_dcb_nl.c index 6ab1f1abaa01..e75a3c91198d 100644 --- a/drivers/net/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ixgbe/ixgbe_dcb_nl.c | |||
@@ -606,7 +606,98 @@ static u8 ixgbe_dcbnl_setapp(struct net_device *netdev, | |||
606 | return rval; | 606 | return rval; |
607 | } | 607 | } |
608 | 608 | ||
609 | static int ixgbe_dcbnl_ieee_getets(struct net_device *dev, | ||
610 | struct ieee_ets *ets) | ||
611 | { | ||
612 | struct ixgbe_adapter *adapter = netdev_priv(dev); | ||
613 | struct ieee_ets *my_ets = adapter->ixgbe_ieee_ets; | ||
614 | |||
615 | /* No IEEE PFC settings available */ | ||
616 | if (!my_ets) | ||
617 | return -EINVAL; | ||
618 | |||
619 | ets->ets_cap = MAX_TRAFFIC_CLASS; | ||
620 | ets->cbs = my_ets->cbs; | ||
621 | memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw)); | ||
622 | memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw)); | ||
623 | memcpy(ets->tc_tsa, my_ets->tc_tsa, sizeof(ets->tc_tsa)); | ||
624 | memcpy(ets->prio_tc, my_ets->prio_tc, sizeof(ets->prio_tc)); | ||
625 | return 0; | ||
626 | } | ||
627 | |||
628 | static int ixgbe_dcbnl_ieee_setets(struct net_device *dev, | ||
629 | struct ieee_ets *ets) | ||
630 | { | ||
631 | struct ixgbe_adapter *adapter = netdev_priv(dev); | ||
632 | __u16 refill[IEEE_8021QAZ_MAX_TCS], max[IEEE_8021QAZ_MAX_TCS]; | ||
633 | int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN; | ||
634 | int err; | ||
635 | /* naively give each TC a bwg to map onto CEE hardware */ | ||
636 | __u8 bwg_id[IEEE_8021QAZ_MAX_TCS] = {0, 1, 2, 3, 4, 5, 6, 7}; | ||
637 | |||
638 | if (!adapter->ixgbe_ieee_ets) { | ||
639 | adapter->ixgbe_ieee_ets = kmalloc(sizeof(struct ieee_ets), | ||
640 | GFP_KERNEL); | ||
641 | if (!adapter->ixgbe_ieee_ets) | ||
642 | return -ENOMEM; | ||
643 | } | ||
644 | |||
645 | |||
646 | memcpy(adapter->ixgbe_ieee_ets, ets, sizeof(*adapter->ixgbe_ieee_ets)); | ||
647 | |||
648 | ixgbe_ieee_credits(ets->tc_tx_bw, refill, max, max_frame); | ||
649 | err = ixgbe_dcb_hw_ets_config(&adapter->hw, refill, max, | ||
650 | bwg_id, ets->tc_tsa); | ||
651 | return err; | ||
652 | } | ||
653 | |||
654 | static int ixgbe_dcbnl_ieee_getpfc(struct net_device *dev, | ||
655 | struct ieee_pfc *pfc) | ||
656 | { | ||
657 | struct ixgbe_adapter *adapter = netdev_priv(dev); | ||
658 | struct ieee_pfc *my_pfc = adapter->ixgbe_ieee_pfc; | ||
659 | int i; | ||
660 | |||
661 | /* No IEEE PFC settings available */ | ||
662 | if (!my_pfc) | ||
663 | return -EINVAL; | ||
664 | |||
665 | pfc->pfc_cap = MAX_TRAFFIC_CLASS; | ||
666 | pfc->pfc_en = my_pfc->pfc_en; | ||
667 | pfc->mbc = my_pfc->mbc; | ||
668 | pfc->delay = my_pfc->delay; | ||
669 | |||
670 | for (i = 0; i < MAX_TRAFFIC_CLASS; i++) { | ||
671 | pfc->requests[i] = adapter->stats.pxoffrxc[i]; | ||
672 | pfc->indications[i] = adapter->stats.pxofftxc[i]; | ||
673 | } | ||
674 | |||
675 | return 0; | ||
676 | } | ||
677 | |||
678 | static int ixgbe_dcbnl_ieee_setpfc(struct net_device *dev, | ||
679 | struct ieee_pfc *pfc) | ||
680 | { | ||
681 | struct ixgbe_adapter *adapter = netdev_priv(dev); | ||
682 | int err; | ||
683 | |||
684 | if (!adapter->ixgbe_ieee_pfc) { | ||
685 | adapter->ixgbe_ieee_pfc = kmalloc(sizeof(struct ieee_pfc), | ||
686 | GFP_KERNEL); | ||
687 | if (!adapter->ixgbe_ieee_pfc) | ||
688 | return -ENOMEM; | ||
689 | } | ||
690 | |||
691 | memcpy(adapter->ixgbe_ieee_pfc, pfc, sizeof(*adapter->ixgbe_ieee_pfc)); | ||
692 | err = ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc->pfc_en); | ||
693 | return err; | ||
694 | } | ||
695 | |||
609 | const struct dcbnl_rtnl_ops dcbnl_ops = { | 696 | const struct dcbnl_rtnl_ops dcbnl_ops = { |
697 | .ieee_getets = ixgbe_dcbnl_ieee_getets, | ||
698 | .ieee_setets = ixgbe_dcbnl_ieee_setets, | ||
699 | .ieee_getpfc = ixgbe_dcbnl_ieee_getpfc, | ||
700 | .ieee_setpfc = ixgbe_dcbnl_ieee_setpfc, | ||
610 | .getstate = ixgbe_dcbnl_get_state, | 701 | .getstate = ixgbe_dcbnl_get_state, |
611 | .setstate = ixgbe_dcbnl_set_state, | 702 | .setstate = ixgbe_dcbnl_set_state, |
612 | .getpermhwaddr = ixgbe_dcbnl_get_perm_hw_addr, | 703 | .getpermhwaddr = ixgbe_dcbnl_get_perm_hw_addr, |
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c index 1e4814875945..c2e09b9cff46 100644 --- a/drivers/net/ixgbe/ixgbe_main.c +++ b/drivers/net/ixgbe/ixgbe_main.c | |||
@@ -5609,6 +5609,10 @@ static int __ixgbe_shutdown(struct pci_dev *pdev, bool *enable_wake) | |||
5609 | } | 5609 | } |
5610 | 5610 | ||
5611 | ixgbe_clear_interrupt_scheme(adapter); | 5611 | ixgbe_clear_interrupt_scheme(adapter); |
5612 | #ifdef CONFIG_DCB | ||
5613 | kfree(adapter->ixgbe_ieee_pfc); | ||
5614 | kfree(adapter->ixgbe_ieee_ets); | ||
5615 | #endif | ||
5612 | 5616 | ||
5613 | #ifdef CONFIG_PM | 5617 | #ifdef CONFIG_PM |
5614 | retval = pci_save_state(pdev); | 5618 | retval = pci_save_state(pdev); |
diff --git a/include/linux/dcbnl.h b/include/linux/dcbnl.h index 68cd248f6d3e..cd8d518efa3b 100644 --- a/include/linux/dcbnl.h +++ b/include/linux/dcbnl.h | |||
@@ -25,6 +25,11 @@ | |||
25 | /* IEEE 802.1Qaz std supported values */ | 25 | /* IEEE 802.1Qaz std supported values */ |
26 | #define IEEE_8021QAZ_MAX_TCS 8 | 26 | #define IEEE_8021QAZ_MAX_TCS 8 |
27 | 27 | ||
28 | #define IEEE_8021QAZ_TSA_STRICT 0 | ||
29 | #define IEEE_8021QAZ_TSA_CB_SHABER 1 | ||
30 | #define IEEE_8021QAZ_TSA_ETS 2 | ||
31 | #define IEEE_8021QAZ_TSA_VENDOR 255 | ||
32 | |||
28 | /* This structure contains the IEEE 802.1Qaz ETS managed object | 33 | /* This structure contains the IEEE 802.1Qaz ETS managed object |
29 | * | 34 | * |
30 | * @willing: willing bit in ETS configuratin TLV | 35 | * @willing: willing bit in ETS configuratin TLV |