2 * Copyright (C) 2007 Michael Brown <mbrown@fensystems.co.uk>.
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.
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.
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.
19 FILE_LICENCE ( GPL2_OR_LATER
);
34 /** List of all UNDI ROMs */
35 static LIST_HEAD ( undiroms
);
38 * Parse PXE ROM ID structure
41 * @v pxeromid Offset within ROM to PXE ROM ID structure
42 * @ret rc Return status code
44 static int undirom_parse_pxeromid ( struct undi_rom
*undirom
,
45 unsigned int pxeromid
) {
46 struct undi_rom_id undi_rom_id
;
47 unsigned int undiloader
;
49 DBGC ( undirom
, "UNDIROM %p has PXE ROM ID at %04x:%04x\n", undirom
,
50 undirom
->rom_segment
, pxeromid
);
52 /* Read PXE ROM ID structure and verify */
53 copy_from_real ( &undi_rom_id
, undirom
->rom_segment
, pxeromid
,
54 sizeof ( undi_rom_id
) );
55 if ( undi_rom_id
.Signature
!= UNDI_ROM_ID_SIGNATURE
) {
56 DBGC ( undirom
, "UNDIROM %p has bad PXE ROM ID signature "
57 "%08x\n", undirom
, undi_rom_id
.Signature
);
61 /* Check for UNDI loader */
62 undiloader
= undi_rom_id
.UNDILoader
;
64 DBGC ( undirom
, "UNDIROM %p has no UNDI loader\n", undirom
);
68 /* Fill in UNDI ROM loader fields */
69 undirom
->loader_entry
.segment
= undirom
->rom_segment
;
70 undirom
->loader_entry
.offset
= undiloader
;
71 undirom
->code_size
= undi_rom_id
.CodeSize
;
72 undirom
->data_size
= undi_rom_id
.DataSize
;
74 DBGC ( undirom
, "UNDIROM %p has UNDI loader at %04x:%04x "
75 "(code %04zx data %04zx)\n", undirom
,
76 undirom
->loader_entry
.segment
, undirom
->loader_entry
.offset
,
77 undirom
->code_size
, undirom
->data_size
);
82 * Parse PCI expansion header
85 * @v pcirheader Offset within ROM to PCI expansion header
87 static int undirom_parse_pcirheader ( struct undi_rom
*undirom
,
88 unsigned int pcirheader
) {
89 struct pcir_header pcir_header
;
91 DBGC ( undirom
, "UNDIROM %p has PCI expansion header at %04x:%04x\n",
92 undirom
, undirom
->rom_segment
, pcirheader
);
94 /* Read PCI expansion header and verify */
95 copy_from_real ( &pcir_header
, undirom
->rom_segment
, pcirheader
,
96 sizeof ( pcir_header
) );
97 if ( pcir_header
.signature
!= PCIR_SIGNATURE
) {
98 DBGC ( undirom
, "UNDIROM %p has bad PCI expansion header "
99 "signature %08x\n", undirom
, pcir_header
.signature
);
103 /* Fill in UNDI ROM PCI device fields */
104 undirom
->bus_type
= PCI_NIC
;
105 undirom
->bus_id
.pci
.vendor_id
= pcir_header
.vendor_id
;
106 undirom
->bus_id
.pci
.device_id
= pcir_header
.device_id
;
108 DBGC ( undirom
, "UNDIROM %p is for PCI devices %04x:%04x\n", undirom
,
109 undirom
->bus_id
.pci
.vendor_id
, undirom
->bus_id
.pci
.device_id
);
117 * @v rom_segment ROM segment address
118 * @ret rc Return status code
120 static int undirom_probe ( unsigned int rom_segment
) {
121 struct undi_rom
*undirom
= NULL
;
122 struct undi_rom_header romheader
;
124 unsigned int pxeromid
;
125 unsigned int pcirheader
;
128 /* Read expansion ROM header and verify */
129 copy_from_real ( &romheader
, rom_segment
, 0, sizeof ( romheader
) );
130 if ( romheader
.Signature
!= ROM_SIGNATURE
) {
134 rom_len
= ( romheader
.ROMLength
* 512 );
136 /* Allocate memory for UNDI ROM */
137 undirom
= zalloc ( sizeof ( *undirom
) );
139 DBG ( "Could not allocate UNDI ROM structure\n" );
143 DBGC ( undirom
, "UNDIROM %p trying expansion ROM at %04x:0000 "
144 "(%zdkB)\n", undirom
, rom_segment
, ( rom_len
/ 1024 ) );
145 undirom
->rom_segment
= rom_segment
;
147 /* Check for and parse PXE ROM ID */
148 pxeromid
= romheader
.PXEROMID
;
150 DBGC ( undirom
, "UNDIROM %p has no PXE ROM ID\n", undirom
);
154 if ( pxeromid
> rom_len
) {
155 DBGC ( undirom
, "UNDIROM %p PXE ROM ID outside ROM\n",
160 if ( ( rc
= undirom_parse_pxeromid ( undirom
, pxeromid
) ) != 0 )
163 /* Parse PCIR header, if present */
164 pcirheader
= romheader
.PCIRHeader
;
166 undirom_parse_pcirheader ( undirom
, pcirheader
);
168 /* Add to UNDI ROM list and return */
169 DBGC ( undirom
, "UNDIROM %p registered\n", undirom
);
170 list_add ( &undirom
->list
, &undiroms
);
179 * Create UNDI ROMs for all possible expansion ROMs
183 static void undirom_probe_all_roms ( void ) {
184 static int probed
= 0;
185 unsigned int rom_segment
;
187 /* Perform probe only once */
191 DBG ( "Scanning for PXE expansion ROMs\n" );
193 /* Scan through expansion ROM region at 512 byte intervals */
194 for ( rom_segment
= 0xc000 ; rom_segment
< 0x10000 ;
195 rom_segment
+= 0x20 ) {
196 undirom_probe ( rom_segment
);
203 * Find UNDI ROM for PCI device
205 * @v vendor_id PCI vendor ID
206 * @v device_id PCI device ID
207 * @v rombase ROM base address, or 0 for any
208 * @ret undirom UNDI ROM, or NULL
210 struct undi_rom
* undirom_find_pci ( unsigned int vendor_id
,
211 unsigned int device_id
,
212 unsigned int rombase
) {
213 struct undi_rom
*undirom
;
215 undirom_probe_all_roms();
217 list_for_each_entry ( undirom
, &undiroms
, list
) {
218 if ( undirom
->bus_type
!= PCI_NIC
)
220 if ( undirom
->bus_id
.pci
.vendor_id
!= vendor_id
)
222 if ( undirom
->bus_id
.pci
.device_id
!= device_id
)
224 if ( rombase
&& ( ( undirom
->rom_segment
<< 4 ) != rombase
) )
226 DBGC ( undirom
, "UNDIROM %p matched PCI %04x:%04x (%08x)\n",
227 undirom
, vendor_id
, device_id
, rombase
);
231 DBG ( "No UNDI ROM matched PCI %04x:%04x (%08x)\n",
232 vendor_id
, device_id
, rombase
);