4949#define ETHTOOL_ADD_ADVERTISED_LINK_MODE (ecmd , mode ) \
5050 ((ecmd)->advertising |= ADVERTISED_##mode)
5151
52+ #define COALESCE_PENDING_LIMIT_UNIT 8
53+ #define COALESCE_TIMER_CFG_UNIT 9
54+ #define COALESCE_ALL_QUEUE 0xFFFF
55+ #define COALESCE_MAX_PENDING_LIMIT (255 * COALESCE_PENDING_LIMIT_UNIT)
56+ #define COALESCE_MAX_TIMER_CFG (255 * COALESCE_TIMER_CFG_UNIT)
57+ #define OBJ_STR_MAX_LEN 32
58+
5259struct hw2ethtool_link_mode {
5360 enum ethtool_link_mode_bit_indices link_mode_bit ;
5461 u32 speed ;
@@ -614,6 +621,215 @@ static int hinic_set_ringparam(struct net_device *netdev,
614621 return 0 ;
615622}
616623
624+ static int __hinic_get_coalesce (struct net_device * netdev ,
625+ struct ethtool_coalesce * coal , u16 queue )
626+ {
627+ struct hinic_dev * nic_dev = netdev_priv (netdev );
628+ struct hinic_intr_coal_info * rx_intr_coal_info ;
629+ struct hinic_intr_coal_info * tx_intr_coal_info ;
630+
631+ if (queue == COALESCE_ALL_QUEUE ) {
632+ /* get tx/rx irq0 as default parameters */
633+ rx_intr_coal_info = & nic_dev -> rx_intr_coalesce [0 ];
634+ tx_intr_coal_info = & nic_dev -> tx_intr_coalesce [0 ];
635+ } else {
636+ if (queue >= nic_dev -> num_qps ) {
637+ netif_err (nic_dev , drv , netdev ,
638+ "Invalid queue_id: %d\n" , queue );
639+ return - EINVAL ;
640+ }
641+ rx_intr_coal_info = & nic_dev -> rx_intr_coalesce [queue ];
642+ tx_intr_coal_info = & nic_dev -> tx_intr_coalesce [queue ];
643+ }
644+
645+ /* coalesce_timer is in unit of 9us */
646+ coal -> rx_coalesce_usecs = rx_intr_coal_info -> coalesce_timer_cfg *
647+ COALESCE_TIMER_CFG_UNIT ;
648+ /* coalesced_frames is in unit of 8 */
649+ coal -> rx_max_coalesced_frames = rx_intr_coal_info -> pending_limt *
650+ COALESCE_PENDING_LIMIT_UNIT ;
651+ coal -> tx_coalesce_usecs = tx_intr_coal_info -> coalesce_timer_cfg *
652+ COALESCE_TIMER_CFG_UNIT ;
653+ coal -> tx_max_coalesced_frames = tx_intr_coal_info -> pending_limt *
654+ COALESCE_PENDING_LIMIT_UNIT ;
655+
656+ return 0 ;
657+ }
658+
659+ static int is_coalesce_exceed_limit (const struct ethtool_coalesce * coal )
660+ {
661+ if (coal -> rx_coalesce_usecs > COALESCE_MAX_TIMER_CFG ||
662+ coal -> rx_max_coalesced_frames > COALESCE_MAX_PENDING_LIMIT ||
663+ coal -> tx_coalesce_usecs > COALESCE_MAX_TIMER_CFG ||
664+ coal -> tx_max_coalesced_frames > COALESCE_MAX_PENDING_LIMIT )
665+ return - ERANGE ;
666+
667+ return 0 ;
668+ }
669+
670+ static int set_queue_coalesce (struct hinic_dev * nic_dev , u16 q_id ,
671+ struct hinic_intr_coal_info * coal ,
672+ bool set_rx_coal )
673+ {
674+ struct hinic_intr_coal_info * intr_coal = NULL ;
675+ struct hinic_msix_config interrupt_info = {0 };
676+ struct net_device * netdev = nic_dev -> netdev ;
677+ u16 msix_idx ;
678+ int err ;
679+
680+ intr_coal = set_rx_coal ? & nic_dev -> rx_intr_coalesce [q_id ] :
681+ & nic_dev -> tx_intr_coalesce [q_id ];
682+
683+ intr_coal -> coalesce_timer_cfg = coal -> coalesce_timer_cfg ;
684+ intr_coal -> pending_limt = coal -> pending_limt ;
685+
686+ /* netdev not running or qp not in using,
687+ * don't need to set coalesce to hw
688+ */
689+ if (!(nic_dev -> flags & HINIC_INTF_UP ) ||
690+ q_id >= nic_dev -> num_qps )
691+ return 0 ;
692+
693+ msix_idx = set_rx_coal ? nic_dev -> rxqs [q_id ].rq -> msix_entry :
694+ nic_dev -> txqs [q_id ].sq -> msix_entry ;
695+ interrupt_info .msix_index = msix_idx ;
696+ interrupt_info .coalesce_timer_cnt = intr_coal -> coalesce_timer_cfg ;
697+ interrupt_info .pending_cnt = intr_coal -> pending_limt ;
698+ interrupt_info .resend_timer_cnt = intr_coal -> resend_timer_cfg ;
699+
700+ err = hinic_set_interrupt_cfg (nic_dev -> hwdev , & interrupt_info );
701+ if (err )
702+ netif_warn (nic_dev , drv , netdev ,
703+ "Failed to set %s queue%d coalesce" ,
704+ set_rx_coal ? "rx" : "tx" , q_id );
705+
706+ return err ;
707+ }
708+
709+ static int __set_hw_coal_param (struct hinic_dev * nic_dev ,
710+ struct hinic_intr_coal_info * intr_coal ,
711+ u16 queue , bool set_rx_coal )
712+ {
713+ int err ;
714+ u16 i ;
715+
716+ if (queue == COALESCE_ALL_QUEUE ) {
717+ for (i = 0 ; i < nic_dev -> max_qps ; i ++ ) {
718+ err = set_queue_coalesce (nic_dev , i , intr_coal ,
719+ set_rx_coal );
720+ if (err )
721+ return err ;
722+ }
723+ } else {
724+ if (queue >= nic_dev -> num_qps ) {
725+ netif_err (nic_dev , drv , nic_dev -> netdev ,
726+ "Invalid queue_id: %d\n" , queue );
727+ return - EINVAL ;
728+ }
729+ err = set_queue_coalesce (nic_dev , queue , intr_coal ,
730+ set_rx_coal );
731+ if (err )
732+ return err ;
733+ }
734+
735+ return 0 ;
736+ }
737+
738+ static int __hinic_set_coalesce (struct net_device * netdev ,
739+ struct ethtool_coalesce * coal , u16 queue )
740+ {
741+ struct hinic_intr_coal_info * ori_rx_intr_coal = NULL ;
742+ struct hinic_intr_coal_info * ori_tx_intr_coal = NULL ;
743+ struct hinic_dev * nic_dev = netdev_priv (netdev );
744+ struct hinic_intr_coal_info rx_intr_coal = {0 };
745+ struct hinic_intr_coal_info tx_intr_coal = {0 };
746+ char obj_str [OBJ_STR_MAX_LEN ] = {0 };
747+ bool set_rx_coal = false;
748+ bool set_tx_coal = false;
749+ int err ;
750+
751+ err = is_coalesce_exceed_limit (coal );
752+ if (err )
753+ return err ;
754+
755+ if (coal -> rx_coalesce_usecs || coal -> rx_max_coalesced_frames ) {
756+ rx_intr_coal .coalesce_timer_cfg =
757+ (u8 )(coal -> rx_coalesce_usecs / COALESCE_TIMER_CFG_UNIT );
758+ rx_intr_coal .pending_limt = (u8 )(coal -> rx_max_coalesced_frames /
759+ COALESCE_PENDING_LIMIT_UNIT );
760+ set_rx_coal = true;
761+ }
762+
763+ if (coal -> tx_coalesce_usecs || coal -> tx_max_coalesced_frames ) {
764+ tx_intr_coal .coalesce_timer_cfg =
765+ (u8 )(coal -> tx_coalesce_usecs / COALESCE_TIMER_CFG_UNIT );
766+ tx_intr_coal .pending_limt = (u8 )(coal -> tx_max_coalesced_frames /
767+ COALESCE_PENDING_LIMIT_UNIT );
768+ set_tx_coal = true;
769+ }
770+
771+ if (queue == COALESCE_ALL_QUEUE ) {
772+ ori_rx_intr_coal = & nic_dev -> rx_intr_coalesce [0 ];
773+ ori_tx_intr_coal = & nic_dev -> tx_intr_coalesce [0 ];
774+ err = snprintf (obj_str , OBJ_STR_MAX_LEN , "for netdev" );
775+ } else {
776+ ori_rx_intr_coal = & nic_dev -> rx_intr_coalesce [queue ];
777+ ori_tx_intr_coal = & nic_dev -> tx_intr_coalesce [queue ];
778+ err = snprintf (obj_str , OBJ_STR_MAX_LEN , "for queue %d" , queue );
779+ }
780+ if (err <= 0 || err >= OBJ_STR_MAX_LEN ) {
781+ netif_err (nic_dev , drv , netdev , "Failed to snprintf string, function return(%d) and dest_len(%d)\n" ,
782+ err , OBJ_STR_MAX_LEN );
783+ return - EFAULT ;
784+ }
785+
786+ /* setting coalesce timer or pending limit to zero will disable
787+ * coalesce
788+ */
789+ if (set_rx_coal && (!rx_intr_coal .coalesce_timer_cfg ||
790+ !rx_intr_coal .pending_limt ))
791+ netif_warn (nic_dev , drv , netdev , "RX coalesce will be disabled\n" );
792+ if (set_tx_coal && (!tx_intr_coal .coalesce_timer_cfg ||
793+ !tx_intr_coal .pending_limt ))
794+ netif_warn (nic_dev , drv , netdev , "TX coalesce will be disabled\n" );
795+
796+ if (set_rx_coal ) {
797+ err = __set_hw_coal_param (nic_dev , & rx_intr_coal , queue , true);
798+ if (err )
799+ return err ;
800+ }
801+ if (set_tx_coal ) {
802+ err = __set_hw_coal_param (nic_dev , & tx_intr_coal , queue , false);
803+ if (err )
804+ return err ;
805+ }
806+ return 0 ;
807+ }
808+
809+ static int hinic_get_coalesce (struct net_device * netdev ,
810+ struct ethtool_coalesce * coal )
811+ {
812+ return __hinic_get_coalesce (netdev , coal , COALESCE_ALL_QUEUE );
813+ }
814+
815+ static int hinic_set_coalesce (struct net_device * netdev ,
816+ struct ethtool_coalesce * coal )
817+ {
818+ return __hinic_set_coalesce (netdev , coal , COALESCE_ALL_QUEUE );
819+ }
820+
821+ static int hinic_get_per_queue_coalesce (struct net_device * netdev , u32 queue ,
822+ struct ethtool_coalesce * coal )
823+ {
824+ return __hinic_get_coalesce (netdev , coal , queue );
825+ }
826+
827+ static int hinic_set_per_queue_coalesce (struct net_device * netdev , u32 queue ,
828+ struct ethtool_coalesce * coal )
829+ {
830+ return __hinic_set_coalesce (netdev , coal , queue );
831+ }
832+
617833static void hinic_get_pauseparam (struct net_device * netdev ,
618834 struct ethtool_pauseparam * pause )
619835{
@@ -1293,12 +1509,21 @@ static void hinic_get_strings(struct net_device *netdev,
12931509}
12941510
12951511static const struct ethtool_ops hinic_ethtool_ops = {
1512+ .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
1513+ ETHTOOL_COALESCE_RX_MAX_FRAMES |
1514+ ETHTOOL_COALESCE_TX_USECS |
1515+ ETHTOOL_COALESCE_TX_MAX_FRAMES ,
1516+
12961517 .get_link_ksettings = hinic_get_link_ksettings ,
12971518 .set_link_ksettings = hinic_set_link_ksettings ,
12981519 .get_drvinfo = hinic_get_drvinfo ,
12991520 .get_link = ethtool_op_get_link ,
13001521 .get_ringparam = hinic_get_ringparam ,
13011522 .set_ringparam = hinic_set_ringparam ,
1523+ .get_coalesce = hinic_get_coalesce ,
1524+ .set_coalesce = hinic_set_coalesce ,
1525+ .get_per_queue_coalesce = hinic_get_per_queue_coalesce ,
1526+ .set_per_queue_coalesce = hinic_set_per_queue_coalesce ,
13021527 .get_pauseparam = hinic_get_pauseparam ,
13031528 .set_pauseparam = hinic_set_pauseparam ,
13041529 .get_channels = hinic_get_channels ,
@@ -1315,11 +1540,20 @@ static const struct ethtool_ops hinic_ethtool_ops = {
13151540};
13161541
13171542static const struct ethtool_ops hinicvf_ethtool_ops = {
1543+ .supported_coalesce_params = ETHTOOL_COALESCE_RX_USECS |
1544+ ETHTOOL_COALESCE_RX_MAX_FRAMES |
1545+ ETHTOOL_COALESCE_TX_USECS |
1546+ ETHTOOL_COALESCE_TX_MAX_FRAMES ,
1547+
13181548 .get_link_ksettings = hinic_get_link_ksettings ,
13191549 .get_drvinfo = hinic_get_drvinfo ,
13201550 .get_link = ethtool_op_get_link ,
13211551 .get_ringparam = hinic_get_ringparam ,
13221552 .set_ringparam = hinic_set_ringparam ,
1553+ .get_coalesce = hinic_get_coalesce ,
1554+ .set_coalesce = hinic_set_coalesce ,
1555+ .get_per_queue_coalesce = hinic_get_per_queue_coalesce ,
1556+ .set_per_queue_coalesce = hinic_set_per_queue_coalesce ,
13231557 .get_channels = hinic_get_channels ,
13241558 .set_channels = hinic_set_channels ,
13251559 .get_rxnfc = hinic_get_rxnfc ,
0 commit comments