@@ -228,6 +228,63 @@ static void fbnic_mbx_process_tx_msgs(struct fbnic_dev *fbd)
228
228
tx_mbx -> head = head ;
229
229
}
230
230
231
+ static int fbnic_mbx_map_req_w_cmpl (struct fbnic_dev * fbd ,
232
+ struct fbnic_tlv_msg * msg ,
233
+ struct fbnic_fw_completion * cmpl_data )
234
+ {
235
+ unsigned long flags ;
236
+ int err ;
237
+
238
+ spin_lock_irqsave (& fbd -> fw_tx_lock , flags );
239
+
240
+ /* If we are already waiting on a completion then abort */
241
+ if (cmpl_data && fbd -> cmpl_data ) {
242
+ err = - EBUSY ;
243
+ goto unlock_mbx ;
244
+ }
245
+
246
+ /* Record completion location and submit request */
247
+ if (cmpl_data )
248
+ fbd -> cmpl_data = cmpl_data ;
249
+
250
+ err = fbnic_mbx_map_msg (fbd , FBNIC_IPC_MBX_TX_IDX , msg ,
251
+ le16_to_cpu (msg -> hdr .len ) * sizeof (u32 ), 1 );
252
+
253
+ /* If msg failed then clear completion data for next caller */
254
+ if (err && cmpl_data )
255
+ fbd -> cmpl_data = NULL ;
256
+
257
+ unlock_mbx :
258
+ spin_unlock_irqrestore (& fbd -> fw_tx_lock , flags );
259
+
260
+ return err ;
261
+ }
262
+
263
+ static void fbnic_fw_release_cmpl_data (struct kref * kref )
264
+ {
265
+ struct fbnic_fw_completion * cmpl_data ;
266
+
267
+ cmpl_data = container_of (kref , struct fbnic_fw_completion ,
268
+ ref_count );
269
+ kfree (cmpl_data );
270
+ }
271
+
272
+ static struct fbnic_fw_completion *
273
+ fbnic_fw_get_cmpl_by_type (struct fbnic_dev * fbd , u32 msg_type )
274
+ {
275
+ struct fbnic_fw_completion * cmpl_data = NULL ;
276
+ unsigned long flags ;
277
+
278
+ spin_lock_irqsave (& fbd -> fw_tx_lock , flags );
279
+ if (fbd -> cmpl_data && fbd -> cmpl_data -> msg_type == msg_type ) {
280
+ cmpl_data = fbd -> cmpl_data ;
281
+ kref_get (& fbd -> cmpl_data -> ref_count );
282
+ }
283
+ spin_unlock_irqrestore (& fbd -> fw_tx_lock , flags );
284
+
285
+ return cmpl_data ;
286
+ }
287
+
231
288
/**
232
289
* fbnic_fw_xmit_simple_msg - Transmit a simple single TLV message w/o data
233
290
* @fbd: FBNIC device structure
@@ -651,13 +708,94 @@ void fbnic_fw_check_heartbeat(struct fbnic_dev *fbd)
651
708
dev_warn (fbd -> dev , "Failed to send heartbeat message\n" );
652
709
}
653
710
711
+ /**
712
+ * fbnic_fw_xmit_tsene_read_msg - Create and transmit a sensor read request
713
+ * @fbd: FBNIC device structure
714
+ * @cmpl_data: Completion data structure to store sensor response
715
+ *
716
+ * Asks the firmware to provide an update with the latest sensor data.
717
+ * The response will contain temperature and voltage readings.
718
+ *
719
+ * Return: 0 on success, negative error value on failure
720
+ */
721
+ int fbnic_fw_xmit_tsene_read_msg (struct fbnic_dev * fbd ,
722
+ struct fbnic_fw_completion * cmpl_data )
723
+ {
724
+ struct fbnic_tlv_msg * msg ;
725
+ int err ;
726
+
727
+ if (!fbnic_fw_present (fbd ))
728
+ return - ENODEV ;
729
+
730
+ msg = fbnic_tlv_msg_alloc (FBNIC_TLV_MSG_ID_TSENE_READ_REQ );
731
+ if (!msg )
732
+ return - ENOMEM ;
733
+
734
+ err = fbnic_mbx_map_req_w_cmpl (fbd , msg , cmpl_data );
735
+ if (err )
736
+ goto free_message ;
737
+
738
+ return 0 ;
739
+
740
+ free_message :
741
+ free_page ((unsigned long )msg );
742
+ return err ;
743
+ }
744
+
745
+ static const struct fbnic_tlv_index fbnic_tsene_read_resp_index [] = {
746
+ FBNIC_TLV_ATTR_S32 (FBNIC_TSENE_THERM ),
747
+ FBNIC_TLV_ATTR_S32 (FBNIC_TSENE_VOLT ),
748
+ FBNIC_TLV_ATTR_S32 (FBNIC_TSENE_ERROR ),
749
+ FBNIC_TLV_ATTR_LAST
750
+ };
751
+
752
+ static int fbnic_fw_parse_tsene_read_resp (void * opaque ,
753
+ struct fbnic_tlv_msg * * results )
754
+ {
755
+ struct fbnic_fw_completion * cmpl_data ;
756
+ struct fbnic_dev * fbd = opaque ;
757
+ int err = 0 ;
758
+
759
+ /* Verify we have a completion pointer to provide with data */
760
+ cmpl_data = fbnic_fw_get_cmpl_by_type (fbd ,
761
+ FBNIC_TLV_MSG_ID_TSENE_READ_RESP );
762
+ if (!cmpl_data )
763
+ return - EINVAL ;
764
+
765
+ if (results [FBNIC_TSENE_ERROR ]) {
766
+ err = fbnic_tlv_attr_get_unsigned (results [FBNIC_TSENE_ERROR ]);
767
+ if (err )
768
+ goto exit_complete ;
769
+ }
770
+
771
+ if (!results [FBNIC_TSENE_THERM ] || !results [FBNIC_TSENE_VOLT ]) {
772
+ err = - EINVAL ;
773
+ goto exit_complete ;
774
+ }
775
+
776
+ cmpl_data -> u .tsene .millidegrees =
777
+ fbnic_tlv_attr_get_signed (results [FBNIC_TSENE_THERM ]);
778
+ cmpl_data -> u .tsene .millivolts =
779
+ fbnic_tlv_attr_get_signed (results [FBNIC_TSENE_VOLT ]);
780
+
781
+ exit_complete :
782
+ cmpl_data -> result = err ;
783
+ complete (& cmpl_data -> done );
784
+ fbnic_fw_put_cmpl (cmpl_data );
785
+
786
+ return err ;
787
+ }
788
+
654
789
static const struct fbnic_tlv_parser fbnic_fw_tlv_parser [] = {
655
790
FBNIC_TLV_PARSER (FW_CAP_RESP , fbnic_fw_cap_resp_index ,
656
791
fbnic_fw_parse_cap_resp ),
657
792
FBNIC_TLV_PARSER (OWNERSHIP_RESP , fbnic_ownership_resp_index ,
658
793
fbnic_fw_parse_ownership_resp ),
659
794
FBNIC_TLV_PARSER (HEARTBEAT_RESP , fbnic_heartbeat_resp_index ,
660
795
fbnic_fw_parse_heartbeat_resp ),
796
+ FBNIC_TLV_PARSER (TSENE_READ_RESP ,
797
+ fbnic_tsene_read_resp_index ,
798
+ fbnic_fw_parse_tsene_read_resp ),
661
799
FBNIC_TLV_MSG_ERROR
662
800
};
663
801
@@ -802,3 +940,25 @@ void fbnic_get_fw_ver_commit_str(struct fbnic_dev *fbd, char *fw_version,
802
940
fbnic_mk_full_fw_ver_str (mgmt -> version , delim , mgmt -> commit ,
803
941
fw_version , str_sz );
804
942
}
943
+
944
+ void fbnic_fw_init_cmpl (struct fbnic_fw_completion * fw_cmpl ,
945
+ u32 msg_type )
946
+ {
947
+ fw_cmpl -> msg_type = msg_type ;
948
+ init_completion (& fw_cmpl -> done );
949
+ kref_init (& fw_cmpl -> ref_count );
950
+ }
951
+
952
+ void fbnic_fw_clear_compl (struct fbnic_dev * fbd )
953
+ {
954
+ unsigned long flags ;
955
+
956
+ spin_lock_irqsave (& fbd -> fw_tx_lock , flags );
957
+ fbd -> cmpl_data = NULL ;
958
+ spin_unlock_irqrestore (& fbd -> fw_tx_lock , flags );
959
+ }
960
+
961
+ void fbnic_fw_put_cmpl (struct fbnic_fw_completion * fw_cmpl )
962
+ {
963
+ kref_put (& fw_cmpl -> ref_count , fbnic_fw_release_cmpl_data );
964
+ }
0 commit comments