@@ -158,6 +158,20 @@ static int __rdma_counter_unbind_qp(struct ib_qp *qp)
158158 return ret ;
159159}
160160
161+ static void counter_history_stat_update (const struct rdma_counter * counter )
162+ {
163+ struct ib_device * dev = counter -> device ;
164+ struct rdma_port_counter * port_counter ;
165+ int i ;
166+
167+ port_counter = & dev -> port_data [counter -> port ].port_counter ;
168+ if (!port_counter -> hstats )
169+ return ;
170+
171+ for (i = 0 ; i < counter -> stats -> num_counters ; i ++ )
172+ port_counter -> hstats -> value [i ] += counter -> stats -> value [i ];
173+ }
174+
161175/**
162176 * rdma_get_counter_auto_mode - Find the counter that @qp should be bound
163177 * with in auto mode
@@ -215,6 +229,7 @@ static void counter_release(struct kref *kref)
215229 struct rdma_counter * counter ;
216230
217231 counter = container_of (kref , struct rdma_counter , kref );
232+ counter_history_stat_update (counter );
218233 counter -> device -> ops .counter_dealloc (counter );
219234 rdma_counter_free (counter );
220235}
@@ -299,6 +314,55 @@ int rdma_counter_query_stats(struct rdma_counter *counter)
299314 return ret ;
300315}
301316
317+ static u64 get_running_counters_hwstat_sum (struct ib_device * dev ,
318+ u8 port , u32 index )
319+ {
320+ struct rdma_restrack_entry * res ;
321+ struct rdma_restrack_root * rt ;
322+ struct rdma_counter * counter ;
323+ unsigned long id = 0 ;
324+ u64 sum = 0 ;
325+
326+ rt = & dev -> res [RDMA_RESTRACK_COUNTER ];
327+ xa_lock (& rt -> xa );
328+ xa_for_each (& rt -> xa , id , res ) {
329+ if (!rdma_restrack_get (res ))
330+ continue ;
331+
332+ xa_unlock (& rt -> xa );
333+
334+ counter = container_of (res , struct rdma_counter , res );
335+ if ((counter -> device != dev ) || (counter -> port != port ) ||
336+ rdma_counter_query_stats (counter ))
337+ goto next ;
338+
339+ sum += counter -> stats -> value [index ];
340+
341+ next :
342+ xa_lock (& rt -> xa );
343+ rdma_restrack_put (res );
344+ }
345+
346+ xa_unlock (& rt -> xa );
347+ return sum ;
348+ }
349+
350+ /**
351+ * rdma_counter_get_hwstat_value() - Get the sum value of all counters on a
352+ * specific port, including the running ones and history data
353+ */
354+ u64 rdma_counter_get_hwstat_value (struct ib_device * dev , u8 port , u32 index )
355+ {
356+ struct rdma_port_counter * port_counter ;
357+ u64 sum ;
358+
359+ port_counter = & dev -> port_data [port ].port_counter ;
360+ sum = get_running_counters_hwstat_sum (dev , port , index );
361+ sum += port_counter -> hstats -> value [index ];
362+
363+ return sum ;
364+ }
365+
302366void rdma_counter_init (struct ib_device * dev )
303367{
304368 struct rdma_port_counter * port_counter ;
@@ -311,9 +375,34 @@ void rdma_counter_init(struct ib_device *dev)
311375 port_counter = & dev -> port_data [port ].port_counter ;
312376 port_counter -> mode .mode = RDMA_COUNTER_MODE_NONE ;
313377 mutex_init (& port_counter -> lock );
378+
379+ port_counter -> hstats = dev -> ops .alloc_hw_stats (dev , port );
380+ if (!port_counter -> hstats )
381+ goto fail ;
314382 }
383+
384+ return ;
385+
386+ fail :
387+ rdma_for_each_port (dev , port ) {
388+ port_counter = & dev -> port_data [port ].port_counter ;
389+ kfree (port_counter -> hstats );
390+ port_counter -> hstats = NULL ;
391+ }
392+
393+ return ;
315394}
316395
317396void rdma_counter_release (struct ib_device * dev )
318397{
398+ struct rdma_port_counter * port_counter ;
399+ u32 port ;
400+
401+ if (!dev -> ops .alloc_hw_stats )
402+ return ;
403+
404+ rdma_for_each_port (dev , port ) {
405+ port_counter = & dev -> port_data [port ].port_counter ;
406+ kfree (port_counter -> hstats );
407+ }
319408}
0 commit comments