These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / drivers / bus / pcivpd.c
1 /*
2  * Copyright (C) 2010 Michael Brown <mbrown@fensystems.co.uk>.
3  *
4  * This program is free software; you can redistribute it and/or
5  * modify it under the terms of the GNU General Public License as
6  * published by the Free Software Foundation; either version 2 of the
7  * License, or any later version.
8  *
9  * This program is distributed in the hope that it will be useful, but
10  * WITHOUT ANY WARRANTY; without even the implied warranty of
11  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
12  * General Public License for more details.
13  *
14  * You should have received a copy of the GNU General Public License
15  * along with this program; if not, write to the Free Software
16  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
17  * 02110-1301, USA.
18  *
19  * You can also choose to distribute this program under the terms of
20  * the Unmodified Binary Distribution Licence (as given in the file
21  * COPYING.UBDL), provided that you have satisfied its requirements.
22  */
23
24 FILE_LICENCE ( GPL2_OR_LATER_OR_UBDL );
25
26 #include <stdint.h>
27 #include <stdlib.h>
28 #include <unistd.h>
29 #include <errno.h>
30 #include <byteswap.h>
31 #include <ipxe/pci.h>
32 #include <ipxe/isapnp.h>
33 #include <ipxe/pcivpd.h>
34
35 /** @file
36  *
37  * PCI Vital Product Data
38  *
39  */
40
41 /**
42  * Initialise PCI Vital Product Data
43  *
44  * @v vpd               PCI VPD
45  * @v pci               PCI device
46  * @ret rc              Return status code
47  */
48 int pci_vpd_init ( struct pci_vpd *vpd, struct pci_device *pci ) {
49
50         /* Initialise structure */
51         vpd->pci = pci;
52         pci_vpd_invalidate_cache ( vpd );
53
54         /* Locate VPD capability */
55         vpd->cap = pci_find_capability ( pci, PCI_CAP_ID_VPD );
56         if ( ! vpd->cap ) {
57                 DBGC ( vpd, PCI_FMT " does not support VPD\n",
58                        PCI_ARGS ( pci ) );
59                 return -ENOTTY;
60         }
61
62         DBGC ( vpd, PCI_FMT " VPD is at offset %02x\n",
63                PCI_ARGS ( pci ), vpd->cap );
64         return 0;
65 }
66
67 /**
68  * Read one dword of PCI Vital Product Data
69  *
70  * @v vpd               PCI VPD
71  * @v address           Address to read
72  * @ret data            Read data
73  * @ret rc              Return status code
74  */
75 static int pci_vpd_read_dword ( struct pci_vpd *vpd, int address,
76                                 uint32_t *data ) {
77         struct pci_device *pci = vpd->pci;
78         unsigned int cap = vpd->cap;
79         unsigned int retries;
80         uint16_t flag;
81
82         /* Fail if no VPD present */
83         if ( ! cap )
84                 return -ENOTTY;
85
86         /* Return cached value, if present */
87         if ( pci_vpd_cache_is_valid ( vpd ) &&
88              ( vpd->cache.address == address ) ) {
89                 *data = vpd->cache.data;
90                 return 0;
91         }
92
93         /* Initiate read */
94         pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), address );
95
96         /* Wait for read to complete */
97         for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) {
98
99                 /* Check if data is ready */
100                 pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag );
101                 if ( flag & PCI_VPD_FLAG ) {
102
103                         /* Read data */
104                         pci_read_config_dword ( pci, ( cap + PCI_VPD_DATA ),
105                                                 data );
106                         DBGC2 ( vpd, PCI_FMT " VPD %04x => %08x\n",
107                                 PCI_ARGS ( pci ), address, htonl ( *data ) );
108
109                         /* Populate cache */
110                         vpd->cache.address = address;
111                         vpd->cache.data = *data;
112
113                         return 0;
114                 }
115
116                 /* Wait 1ms before retrying */
117                 mdelay ( 1 );
118         }
119
120         DBGC ( vpd, PCI_FMT " VPD %04x read via %02x timed out\n",
121                PCI_ARGS ( pci ), address, cap );
122         return -ETIMEDOUT;
123 }
124
125 /**
126  * Write one dword of PCI Vital Product Data
127  *
128  * @v vpd               PCI VPD
129  * @v address           Address to write
130  * @v data              Data to write
131  * @ret rc              Return status code
132  */
133 static int pci_vpd_write_dword ( struct pci_vpd *vpd, int address,
134                                  uint32_t data ) {
135         struct pci_device *pci = vpd->pci;
136         unsigned int cap = vpd->cap;
137         unsigned int retries;
138         uint16_t flag;
139
140         /* Fail if no VPD present */
141         if ( ! cap )
142                 return -ENOTTY;
143
144         /* Invalidate cache */
145         pci_vpd_invalidate_cache ( vpd );
146
147         DBGC2 ( vpd, PCI_FMT " VPD %04x <= %08x\n",
148                 PCI_ARGS ( pci ), address, htonl ( data ) );
149
150         /* Write data */
151         pci_write_config_dword ( pci, ( cap + PCI_VPD_DATA ), data );
152
153         /* Initiate write */
154         pci_write_config_word ( pci, ( cap + PCI_VPD_ADDRESS ),
155                                 ( address | PCI_VPD_FLAG ) );
156
157         /* Wait for write to complete */
158         for ( retries = 0 ; retries < PCI_VPD_MAX_WAIT_MS ; retries++ ) {
159
160                 /* Check if write has completed */
161                 pci_read_config_word ( pci, ( cap + PCI_VPD_ADDRESS ), &flag );
162                 if ( ! ( flag & PCI_VPD_FLAG ) )
163                         return 0;
164
165                 /* Wait 1ms before retrying */
166                 mdelay ( 1 );
167         }
168
169         DBGC ( vpd, PCI_FMT " VPD %04x write via %02x timed out\n",
170                PCI_ARGS ( pci ), address, cap );
171         return -ETIMEDOUT;
172 }
173
174 /**
175  * Read PCI VPD
176  *
177  * @v vpd               PCI VPD
178  * @v address           Starting address
179  * @v buf               Data buffer
180  * @v len               Length of data buffer
181  * @ret rc              Return status code
182  */
183 int pci_vpd_read ( struct pci_vpd *vpd, unsigned int address, void *buf,
184                    size_t len ) {
185         uint8_t *bytes = buf;
186         uint32_t data;
187         size_t skip_len;
188         unsigned int i;
189         int rc;
190
191         /* Calculate length to skip at start of data */
192         skip_len = ( address & 0x03 );
193
194         /* Read data, a dword at a time */
195         for ( address &= ~0x03 ; len ; address += 4 ) {
196
197                 /* Read whole dword */
198                 if ( ( rc = pci_vpd_read_dword ( vpd, address, &data ) ) != 0 )
199                         return rc;
200
201                 /* Copy data to buffer */
202                 for ( i = 4 ; i ; i-- ) {
203                         if ( skip_len ) {
204                                 skip_len--;
205                         } else if ( len ) {
206                                 *(bytes++) = data;
207                                 len--;
208                         }
209                         data = ( ( data << 24 ) | ( data >> 8 ) );
210                 }
211         }
212
213         return 0;
214 }
215
216 /**
217  * Write PCI VPD
218  *
219  * @v vpd               PCI VPD
220  * @v address           Starting address
221  * @v buf               Data buffer
222  * @v len               Length of data buffer
223  * @ret rc              Return status code
224  */
225 int pci_vpd_write ( struct pci_vpd *vpd, unsigned int address, const void *buf,
226                     size_t len ) {
227         const uint8_t *bytes = buf;
228         uint32_t data;
229         size_t skip_len;
230         unsigned int i;
231         int rc;
232
233         /* Calculate length to skip at start of data */
234         skip_len = ( address & 0x03 );
235
236         /* Write data, a dword at a time */
237         for ( address &= ~0x03 ; len ; address += 4 ) {
238
239                 /* Read existing dword, if necessary */
240                 if ( skip_len || ( len <= 0x03 ) ) {
241                         if ( ( rc = pci_vpd_read_dword ( vpd, address,
242                                                          &data ) ) != 0 )
243                                 return rc;
244                 }
245
246                 /* Copy data from buffer */
247                 for ( i = 4 ; i ; i-- ) {
248                         if ( skip_len ) {
249                                 skip_len--;
250                         } else if ( len ) {
251                                 data = ( ( data & ~0xff ) | *(bytes++) );
252                                 len--;
253                         }
254                         data = ( ( data << 24 ) | ( data >> 8 ) );
255                 }
256
257                 /* Write whole dword */
258                 if ( ( rc = pci_vpd_write_dword ( vpd, address, data ) ) != 0 )
259                         return rc;
260         }
261         return 0;
262 }
263
264 /**
265  * Dump PCI VPD region (for debugging)
266  *
267  * @v vpd               PCI VPD
268  * @v address           Starting address
269  * @v len               Length of data
270  */
271 static void pci_vpd_dump ( struct pci_vpd *vpd, unsigned int address,
272                            size_t len ) {
273         int rc;
274
275         /* Do nothing in non-debug builds */
276         if ( ! DBG_LOG )
277                 return;
278
279         /* Read data */
280         {
281                 char buf[len];
282                 if ( ( rc = pci_vpd_read ( vpd, address, buf,
283                                            sizeof ( buf ) ) ) != 0 )
284                         return;
285                 DBGC_HDA ( vpd, address, buf, sizeof ( buf ) );
286         }
287 }
288
289 /**
290  * Locate PCI VPD tag
291  *
292  * @v vpd               PCI VPD
293  * @v tag               ISAPnP tag
294  * @ret address         Address of tag body
295  * @ret len             Length of tag body
296  * @ret rc              Return status code
297  */
298 static int pci_vpd_find_tag ( struct pci_vpd *vpd, unsigned int tag,
299                               unsigned int *address, size_t *len ) {
300         uint8_t read_tag;
301         uint16_t read_len;
302         int rc;
303
304         /* Scan through tags looking for a match */
305         *address = 0;
306         do {
307                 /* Read tag byte */
308                 if ( ( rc = pci_vpd_read ( vpd, (*address)++, &read_tag,
309                                            sizeof ( read_tag ) ) ) != 0 )
310                         return rc;
311
312                 /* Extract tag and length */
313                 if ( ISAPNP_IS_LARGE_TAG ( read_tag ) ) {
314                         if ( ( rc = pci_vpd_read ( vpd, *address, &read_len,
315                                                    sizeof ( read_len ) ) ) != 0)
316                                 return rc;
317                         *address += sizeof ( read_len );
318                         read_len = le16_to_cpu ( read_len );
319                         read_tag = ISAPNP_LARGE_TAG_NAME ( read_tag );
320                 } else {
321                         read_len = ISAPNP_SMALL_TAG_LEN ( read_tag );
322                         read_tag = ISAPNP_SMALL_TAG_NAME ( read_tag );
323                 }
324
325                 /* Check for tag match */
326                 if ( tag == read_tag ) {
327                         *len = read_len;
328                         DBGC ( vpd, PCI_FMT " VPD tag %02x is at "
329                                "[%04x,%04zx)\n", PCI_ARGS ( vpd->pci ), tag,
330                                *address, ( *address + *len ) );
331                         return 0;
332                 }
333
334                 /* Move to next tag */
335                 *address += read_len;
336
337         } while ( read_tag != ISAPNP_TAG_END );
338
339         DBGC ( vpd, PCI_FMT " VPD tag %02x not found\n",
340                PCI_ARGS ( vpd->pci ), tag );
341         return -ENOENT;
342 }
343
344 /**
345  * Locate PCI VPD field
346  *
347  * @v vpd               PCI VPD
348  * @v field             VPD field descriptor
349  * @ret address         Address of field body
350  * @ret len             Length of field body
351  * @ret rc              Return status code
352  */
353 int pci_vpd_find ( struct pci_vpd *vpd, unsigned int field,
354                    unsigned int *address, size_t *len ) {
355         struct pci_vpd_field read_field;
356         int rc;
357
358         /* Locate containing tag */
359         if ( ( rc = pci_vpd_find_tag ( vpd, PCI_VPD_TAG ( field ),
360                                        address, len ) ) != 0 )
361                 return rc;
362
363         /* Return immediately if we are searching for a whole-tag field */
364         if ( ! PCI_VPD_KEYWORD ( field ) ) {
365                 pci_vpd_dump ( vpd, *address, *len );
366                 return 0;
367         }
368
369         /* Scan through fields looking for a match */
370         while ( *len >= sizeof ( read_field ) ) {
371
372                 /* Read field header */
373                 if ( ( rc = pci_vpd_read ( vpd, *address, &read_field,
374                                            sizeof ( read_field ) ) ) != 0 )
375                         return rc;
376                 *address += sizeof ( read_field );
377                 *len -= sizeof ( read_field );
378
379                 /* Check for keyword match */
380                 if ( read_field.keyword == PCI_VPD_KEYWORD ( field ) ) {
381                         *len = read_field.len;
382                         DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
383                                " is at [%04x,%04zx)\n", PCI_ARGS ( vpd->pci ),
384                                PCI_VPD_FIELD_ARGS ( field ),
385                                *address, ( *address + *len ) );
386                         pci_vpd_dump ( vpd, *address, *len );
387                         return 0;
388                 }
389
390                 /* Move to next field */
391                 if ( read_field.len > *len )
392                         break;
393                 *address += read_field.len;
394                 *len -= read_field.len;
395         }
396
397         DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " not found\n",
398                PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ) );
399         return -ENOENT;
400 }
401
402 /**
403  * Resize VPD field
404  *
405  * @v vpd               PCI VPD
406  * @v field             VPD field descriptor
407  * @v len               New length of field body
408  * @ret address         Address of field body
409  * @ret rc              Return status code
410  */
411 int pci_vpd_resize ( struct pci_vpd *vpd, unsigned int field, size_t len,
412                      unsigned int *address ) {
413         struct pci_vpd_field rw_field;
414         struct pci_vpd_field old_field;
415         struct pci_vpd_field new_field;
416         unsigned int rw_address;
417         unsigned int old_address;
418         unsigned int copy_address;
419         unsigned int dst_address;
420         unsigned int dump_address;
421         size_t rw_len;
422         size_t old_len;
423         size_t available_len;
424         size_t copy_len;
425         size_t dump_len;
426         void *copy;
427         int rc;
428
429         /* Sanity checks */
430         assert ( PCI_VPD_TAG ( field ) == PCI_VPD_TAG_RW );
431         assert ( PCI_VPD_KEYWORD ( field ) != 0 );
432         assert ( field != PCI_VPD_FIELD_RW );
433
434         /* Locate 'RW' field */
435         if ( ( rc = pci_vpd_find ( vpd, PCI_VPD_FIELD_RW, &rw_address,
436                                    &rw_len ) ) != 0 )
437                 goto err_no_rw;
438
439         /* Locate old field, if any */
440         if ( ( rc = pci_vpd_find ( vpd, field, &old_address,
441                                    &old_len ) ) == 0 ) {
442
443                 /* Field already exists */
444                 if ( old_address > rw_address ) {
445                         DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
446                                " at [%04x,%04zx) is after field "
447                                PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
448                                PCI_ARGS ( vpd->pci ),
449                                PCI_VPD_FIELD_ARGS ( field ),
450                                old_address, ( old_address + old_len ),
451                                PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ),
452                                rw_address, ( rw_address + rw_len ) );
453                         rc = -ENXIO;
454                         goto err_after_rw;
455                 }
456                 dst_address = ( old_address - sizeof ( old_field ) );
457                 copy_address = ( old_address + old_len );
458                 copy_len = ( rw_address - sizeof ( rw_field ) - copy_address );
459
460                 /* Calculate available length */
461                 available_len = ( rw_len + old_len );
462
463         } else {
464
465                 /* Field does not yet exist */
466                 dst_address = ( rw_address - sizeof ( rw_field ) );
467                 copy_address = dst_address;
468                 copy_len = 0;
469
470                 /* Calculate available length */
471                 available_len = ( ( rw_len > sizeof ( new_field ) ) ?
472                                   ( rw_len - sizeof ( new_field ) ) : 0 );
473         }
474
475         /* Dump region before changes */
476         dump_address = dst_address;
477         dump_len = ( rw_address + rw_len - dump_address );
478         DBGC ( vpd, PCI_FMT " VPD before resizing field " PCI_VPD_FIELD_FMT
479                " to %zd bytes:\n", PCI_ARGS ( vpd->pci ),
480                PCI_VPD_FIELD_ARGS ( field ), len );
481         pci_vpd_dump ( vpd, dump_address, dump_len );
482
483         /* Check available length */
484         if ( available_len > PCI_VPD_MAX_LEN )
485                 available_len = PCI_VPD_MAX_LEN;
486         if ( len > available_len ) {
487                 DBGC ( vpd, PCI_FMT " VPD no space for field "
488                        PCI_VPD_FIELD_FMT " (need %02zx, have %02zx)\n",
489                        PCI_ARGS ( vpd->pci ), PCI_VPD_FIELD_ARGS ( field ),
490                        len, available_len );
491                 rc = -ENOSPC;
492                 goto err_no_space;
493         }
494
495         /* Preserve intermediate fields, if any */
496         copy = malloc ( copy_len );
497         if ( ! copy ) {
498                 rc = -ENOMEM;
499                 goto err_copy_alloc;
500         }
501         if ( ( rc = pci_vpd_read ( vpd, copy_address, copy, copy_len ) ) != 0 )
502                 goto err_copy_read;
503
504         /* Create new field, if applicable */
505         if ( len ) {
506                 new_field.keyword = PCI_VPD_KEYWORD ( field );
507                 new_field.len = len;
508                 if ( ( rc = pci_vpd_write ( vpd, dst_address, &new_field,
509                                             sizeof ( new_field ) ) ) != 0 )
510                         goto err_new_write;
511                 dst_address += sizeof ( new_field );
512                 *address = dst_address;
513                 DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now "
514                        "at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ),
515                        PCI_VPD_FIELD_ARGS ( field ), dst_address,
516                        ( dst_address + new_field.len ) );
517                 dst_address += len;
518         } else {
519                 DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT
520                        " no longer exists\n", PCI_ARGS ( vpd->pci ),
521                        PCI_VPD_FIELD_ARGS ( field ) );
522         }
523
524         /* Restore intermediate fields, if any */
525         if ( ( rc = pci_vpd_write ( vpd, dst_address, copy, copy_len ) ) != 0 )
526                 goto err_copy_write;
527         dst_address += copy_len;
528
529         /* Create 'RW' field */
530         rw_field.keyword = PCI_VPD_KEYWORD ( PCI_VPD_FIELD_RW );
531         rw_field.len = ( rw_len +
532                          ( rw_address - sizeof ( rw_field ) ) - dst_address );
533         if ( ( rc = pci_vpd_write ( vpd, dst_address, &rw_field,
534                                     sizeof ( rw_field ) ) ) != 0 )
535                 goto err_rw_write;
536         dst_address += sizeof ( rw_field );
537         DBGC ( vpd, PCI_FMT " VPD field " PCI_VPD_FIELD_FMT " is now "
538                "at [%04x,%04x)\n", PCI_ARGS ( vpd->pci ),
539                PCI_VPD_FIELD_ARGS ( PCI_VPD_FIELD_RW ), dst_address,
540                ( dst_address + rw_field.len ) );
541
542         /* Dump region after changes */
543         DBGC ( vpd, PCI_FMT " VPD after resizing field " PCI_VPD_FIELD_FMT
544                " to %zd bytes:\n", PCI_ARGS ( vpd->pci ),
545                PCI_VPD_FIELD_ARGS ( field ), len );
546         pci_vpd_dump ( vpd, dump_address, dump_len );
547
548         rc = 0;
549
550  err_rw_write:
551  err_new_write:
552  err_copy_write:
553  err_copy_read:
554         free ( copy );
555  err_copy_alloc:
556  err_no_space:
557  err_after_rw:
558  err_no_rw:
559         return rc;
560 }