@@ -45,6 +45,121 @@ late_bind_to_xe(struct xe_late_bind *late_bind)
4545 return container_of (late_bind , struct xe_device , late_bind );
4646}
4747
48+ static struct xe_device *
49+ late_bind_fw_to_xe (struct xe_late_bind_fw * lb_fw )
50+ {
51+ return container_of (lb_fw , struct xe_device , late_bind .late_bind_fw [lb_fw -> id ]);
52+ }
53+
54+ /* Refer to the "Late Bind based Firmware Layout" documentation entry for details */
55+ static int parse_cpd_header (struct xe_late_bind_fw * lb_fw ,
56+ const void * data , size_t size , const char * manifest_entry )
57+ {
58+ struct xe_device * xe = late_bind_fw_to_xe (lb_fw );
59+ const struct gsc_cpd_header_v2 * header = data ;
60+ const struct gsc_manifest_header * manifest ;
61+ const struct gsc_cpd_entry * entry ;
62+ size_t min_size = sizeof (* header );
63+ u32 offset ;
64+ int i ;
65+
66+ /* manifest_entry is mandatory */
67+ xe_assert (xe , manifest_entry );
68+
69+ if (size < min_size || header -> header_marker != GSC_CPD_HEADER_MARKER )
70+ return - ENOENT ;
71+
72+ if (header -> header_length < sizeof (struct gsc_cpd_header_v2 )) {
73+ drm_err (& xe -> drm , "%s late binding fw: Invalid CPD header length %u!\n" ,
74+ fw_id_to_name [lb_fw -> id ], header -> header_length );
75+ return - EINVAL ;
76+ }
77+
78+ min_size = header -> header_length + sizeof (struct gsc_cpd_entry ) * header -> num_of_entries ;
79+ if (size < min_size ) {
80+ drm_err (& xe -> drm , "%s late binding fw: too small! %zu < %zu\n" ,
81+ fw_id_to_name [lb_fw -> id ], size , min_size );
82+ return - ENODATA ;
83+ }
84+
85+ /* Look for the manifest first */
86+ entry = (void * )header + header -> header_length ;
87+ for (i = 0 ; i < header -> num_of_entries ; i ++ , entry ++ )
88+ if (strcmp (entry -> name , manifest_entry ) == 0 )
89+ offset = entry -> offset & GSC_CPD_ENTRY_OFFSET_MASK ;
90+
91+ if (!offset ) {
92+ drm_err (& xe -> drm , "%s late binding fw: Failed to find manifest_entry\n" ,
93+ fw_id_to_name [lb_fw -> id ]);
94+ return - ENODATA ;
95+ }
96+
97+ min_size = offset + sizeof (struct gsc_manifest_header );
98+ if (size < min_size ) {
99+ drm_err (& xe -> drm , "%s late binding fw: too small! %zu < %zu\n" ,
100+ fw_id_to_name [lb_fw -> id ], size , min_size );
101+ return - ENODATA ;
102+ }
103+
104+ manifest = data + offset ;
105+
106+ lb_fw -> version = manifest -> fw_version ;
107+
108+ return 0 ;
109+ }
110+
111+ /* Refer to the "Late Bind based Firmware Layout" documentation entry for details */
112+ static int parse_lb_layout (struct xe_late_bind_fw * lb_fw ,
113+ const void * data , size_t size , const char * fpt_entry )
114+ {
115+ struct xe_device * xe = late_bind_fw_to_xe (lb_fw );
116+ const struct csc_fpt_header * header = data ;
117+ const struct csc_fpt_entry * entry ;
118+ size_t min_size = sizeof (* header );
119+ u32 offset ;
120+ int i ;
121+
122+ /* fpt_entry is mandatory */
123+ xe_assert (xe , fpt_entry );
124+
125+ if (size < min_size || header -> header_marker != CSC_FPT_HEADER_MARKER )
126+ return - ENOENT ;
127+
128+ if (header -> header_length < sizeof (struct csc_fpt_header )) {
129+ drm_err (& xe -> drm , "%s late binding fw: Invalid FPT header length %u!\n" ,
130+ fw_id_to_name [lb_fw -> id ], header -> header_length );
131+ return - EINVAL ;
132+ }
133+
134+ min_size = header -> header_length + sizeof (struct csc_fpt_entry ) * header -> num_of_entries ;
135+ if (size < min_size ) {
136+ drm_err (& xe -> drm , "%s late binding fw: too small! %zu < %zu\n" ,
137+ fw_id_to_name [lb_fw -> id ], size , min_size );
138+ return - ENODATA ;
139+ }
140+
141+ /* Look for the cpd header first */
142+ entry = (void * )header + header -> header_length ;
143+ for (i = 0 ; i < header -> num_of_entries ; i ++ , entry ++ )
144+ if (strcmp (entry -> name , fpt_entry ) == 0 )
145+ offset = entry -> offset ;
146+
147+ if (!offset ) {
148+ drm_err (& xe -> drm , "%s late binding fw: Failed to find fpt_entry\n" ,
149+ fw_id_to_name [lb_fw -> id ]);
150+ return - ENODATA ;
151+ }
152+
153+ min_size = offset + sizeof (struct gsc_cpd_header_v2 );
154+ if (size < min_size ) {
155+ drm_err (& xe -> drm , "%s late binding fw: too small! %zu < %zu\n" ,
156+ fw_id_to_name [lb_fw -> id ], size , min_size );
157+ return - ENODATA ;
158+ }
159+
160+ return parse_cpd_header (lb_fw , data + offset , size - offset , "LTES.man" );
161+ }
162+
48163static const char * xe_late_bind_parse_status (uint32_t status )
49164{
50165 switch (status ) {
@@ -224,13 +339,22 @@ static int __xe_late_bind_fw_init(struct xe_late_bind *late_bind, u32 fw_id)
224339 return - ENODATA ;
225340 }
226341
342+ ret = parse_lb_layout (lb_fw , fw -> data , fw -> size , "LTES" );
343+ if (ret )
344+ return ret ;
345+
227346 lb_fw -> payload_size = fw -> size ;
228347 lb_fw -> payload = drmm_kzalloc (& xe -> drm , lb_fw -> payload_size , GFP_KERNEL );
229348 if (!lb_fw -> payload ) {
230349 release_firmware (fw );
231350 return - ENOMEM ;
232351 }
233352
353+ drm_info (& xe -> drm , "Using %s firmware from %s version %u.%u.%u.%u\n" ,
354+ fw_id_to_name [lb_fw -> id ], lb_fw -> blob_path ,
355+ lb_fw -> version .major , lb_fw -> version .minor ,
356+ lb_fw -> version .hotfix , lb_fw -> version .build );
357+
234358 memcpy ((void * )lb_fw -> payload , fw -> data , lb_fw -> payload_size );
235359 release_firmware (fw );
236360 INIT_WORK (& lb_fw -> work , xe_late_bind_work );
0 commit comments