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