Add qemu 2.4.0
[kvmfornfv.git] / qemu / roms / ipxe / src / drivers / nvs / nvsvpd.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
20 FILE_LICENCE ( GPL2_OR_LATER );
21
22 #include <stdio.h>
23 #include <errno.h>
24 #include <ipxe/nvs.h>
25 #include <ipxe/pci.h>
26 #include <ipxe/pcivpd.h>
27 #include <ipxe/nvo.h>
28 #include <ipxe/nvsvpd.h>
29
30 /** @file
31  *
32  * Non-Volatile Storage using Vital Product Data
33  *
34  */
35
36 /**
37  * Read from VPD field
38  *
39  * @v nvs               NVS device
40  * @v field             VPD field descriptor
41  * @v data              Data buffer
42  * @v len               Length of data buffer
43  * @ret rc              Return status code
44  */
45 static int nvs_vpd_read ( struct nvs_device *nvs, unsigned int field,
46                           void *data, size_t len ) {
47         struct nvs_vpd_device *nvsvpd =
48                 container_of ( nvs, struct nvs_vpd_device, nvs );
49         struct pci_device *pci = nvsvpd->vpd.pci;
50         unsigned int address;
51         size_t max_len;
52         int rc;
53
54         /* Allow reading non-existent field */
55         if ( len == 0 )
56                 return 0;
57
58         /* Locate VPD field */
59         if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
60                                    &max_len ) ) != 0 ) {
61                 DBGC ( pci, PCI_FMT " NVS VPD could not locate field "
62                        PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
63                        PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
64                 return rc;
65         }
66
67         /* Sanity check */
68         if ( len > max_len ) {
69                 DBGC ( pci, PCI_FMT " NVS VPD cannot read %#02zx bytes "
70                        "beyond field " PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
71                        PCI_ARGS ( pci ), len, PCI_VPD_FIELD_ARGS ( field ),
72                        address, ( address + max_len ) );
73                 return -ENXIO;
74         }
75
76         /* Read from VPD field */
77         if ( ( rc = pci_vpd_read ( &nvsvpd->vpd, address, data, len ) ) != 0 ) {
78                 DBGC ( pci, PCI_FMT " NVS VPD could not read field "
79                        PCI_VPD_FIELD_FMT " at [%04x,%04zx): %s\n",
80                        PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
81                        address, ( address + len ), strerror ( rc ) );
82                 return rc;
83         }
84
85         return 0;
86 }
87
88 /**
89  * Write to VPD field
90  *
91  * @v nvs               NVS device
92  * @v field             VPD field descriptor
93  * @v data              Data buffer
94  * @v len               Length of data buffer
95  * @ret rc              Return status code
96  */
97 static int nvs_vpd_write ( struct nvs_device *nvs, unsigned int field,
98                            const void *data, size_t len ) {
99         struct nvs_vpd_device *nvsvpd =
100                 container_of ( nvs, struct nvs_vpd_device, nvs );
101         struct pci_device *pci = nvsvpd->vpd.pci;
102         unsigned int address;
103         size_t max_len;
104         int rc;
105
106         /* Locate VPD field */
107         if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
108                                    &max_len ) ) != 0 ) {
109                 DBGC ( pci, PCI_FMT " NVS VPD could not locate field "
110                        PCI_VPD_FIELD_FMT ": %s\n", PCI_ARGS ( pci ),
111                        PCI_VPD_FIELD_ARGS ( field ), strerror ( rc ) );
112                 return rc;
113         }
114
115         /* Sanity check */
116         if ( len > max_len ) {
117                 DBGC ( pci, PCI_FMT " NVS VPD cannot write %#02zx bytes "
118                        "beyond field " PCI_VPD_FIELD_FMT " at [%04x,%04zx)\n",
119                        PCI_ARGS ( pci ), len, PCI_VPD_FIELD_ARGS ( field ),
120                        address, ( address + max_len ) );
121                 return -ENXIO;
122         }
123
124         /* Write field */
125         if ( ( rc = pci_vpd_write ( &nvsvpd->vpd, address, data,
126                                     len ) ) != 0 ) {
127                 DBGC ( pci, PCI_FMT " NVS VPD could not write field "
128                        PCI_VPD_FIELD_FMT " at [%04x,%04zx): %s\n",
129                        PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
130                        address, ( address + len ), strerror ( rc ) );
131                 return rc;
132         }
133
134         return 0;
135 }
136
137 /**
138  * Resize VPD field
139  *
140  * @v nvs               NVS device
141  * @v field             VPD field descriptor
142  * @v data              Data buffer
143  * @v len               Length of data buffer
144  * @ret rc              Return status code
145  */
146 static int nvs_vpd_resize ( struct nvs_device *nvs, unsigned int field,
147                             size_t len ) {
148         struct nvs_vpd_device *nvsvpd =
149                 container_of ( nvs, struct nvs_vpd_device, nvs );
150         struct pci_device *pci = nvsvpd->vpd.pci;
151         unsigned int address;
152         int rc;
153
154         /* Resize field */
155         if ( ( rc = pci_vpd_resize ( &nvsvpd->vpd, field, len,
156                                      &address ) ) != 0 ) {
157                 DBGC ( pci, PCI_FMT " NVS VPD could not resize field "
158                        PCI_VPD_FIELD_FMT " to %#02zx bytes: %s\n",
159                        PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ),
160                        len, strerror ( rc ) );
161                 return rc;
162         }
163
164         return 0;
165 }
166
167 /**
168  * Initialise NVS VPD device
169  *
170  * @v nvsvpd            NVS VPD device
171  * @v pci               PCI device
172  * @ret rc              Return status code
173  */
174 int nvs_vpd_init ( struct nvs_vpd_device *nvsvpd, struct pci_device *pci ) {
175         int rc;
176
177         /* Initialise VPD device */
178         if ( ( rc = pci_vpd_init ( &nvsvpd->vpd, pci ) ) != 0 ) {
179                 DBGC ( pci, PCI_FMT " NVS could not initialise "
180                        "VPD: %s\n", PCI_ARGS ( pci ), strerror ( rc ) );
181                 return rc;
182         }
183
184         /* Initialise NVS device */
185         nvsvpd->nvs.read = nvs_vpd_read;
186         nvsvpd->nvs.write = nvs_vpd_write;
187
188         return 0;
189 }
190
191 /**
192  * Resize non-volatile option storage within NVS VPD device
193  *
194  * @v nvo               Non-volatile options block
195  * @v len               New length
196  * @ret rc              Return status code
197  */
198 static int nvs_vpd_nvo_resize ( struct nvo_block *nvo, size_t len ) {
199         int rc;
200
201         /* Resize VPD field */
202         if ( ( rc = nvs_vpd_resize ( nvo->nvs, nvo->address, len ) ) != 0 )
203                 return rc;
204
205         return 0;
206 }
207
208 /**
209  * Initialise non-volatile option storage within NVS VPD device
210  *
211  * @v nvsvpd            NVS VPD device
212  * @v field             VPD field descriptor
213  * @v nvo               Non-volatile options block
214  * @v refcnt            Containing object reference counter, or NULL
215  */
216 void nvs_vpd_nvo_init ( struct nvs_vpd_device *nvsvpd, unsigned int field,
217                         struct nvo_block *nvo, struct refcnt *refcnt ) {
218         struct pci_device *pci = nvsvpd->vpd.pci;
219         unsigned int address;
220         size_t len;
221         int rc;
222
223         /* Locate VPD field, if present */
224         if ( ( rc = pci_vpd_find ( &nvsvpd->vpd, field, &address,
225                                    &len ) ) != 0 ) {
226                 DBGC ( pci, PCI_FMT " NVS VPD field " PCI_VPD_FIELD_FMT
227                        " not present; assuming empty\n",
228                        PCI_ARGS ( pci ), PCI_VPD_FIELD_ARGS ( field ) );
229                 len = 0;
230         }
231
232         /* Initialise non-volatile options block */
233         nvo_init ( nvo, &nvsvpd->nvs, field, len, nvs_vpd_nvo_resize, refcnt );
234 }