Remove obsolete includes
[people/xl0/gpxe.git] / src / arch / i386 / drivers / net / undirom.c
1 /*
2  * Copyright (C) 2007 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., 675 Mass Ave, Cambridge, MA 02139, USA.
17  */
18
19 #include <stdint.h>
20 #include <stdlib.h>
21 #include <string.h>
22 #include <pxe.h>
23 #include <realmode.h>
24 #include <undirom.h>
25
26 /** @file
27  *
28  * UNDI expansion ROMs
29  *
30  */
31
32 /** List of all UNDI ROMs */
33 static LIST_HEAD ( undiroms );
34
35 /**
36  * Parse PXE ROM ID structure
37  *
38  * @v undirom           UNDI ROM
39  * @v pxeromid          Offset within ROM to PXE ROM ID structure
40  * @ret rc              Return status code
41  */
42 static int undirom_parse_pxeromid ( struct undi_rom *undirom,
43                                    unsigned int pxeromid ) {
44         struct undi_rom_id undi_rom_id;
45         unsigned int undiloader;
46
47         DBGC ( undirom, "UNDIROM %p has PXE ROM ID at %04x:%04x\n", undirom,
48                undirom->rom_segment, pxeromid );
49
50         /* Read PXE ROM ID structure and verify */
51         copy_from_real ( &undi_rom_id, undirom->rom_segment, pxeromid,
52                          sizeof ( undi_rom_id ) );
53         if ( undi_rom_id.Signature != UNDI_ROM_ID_SIGNATURE ) {
54                 DBGC ( undirom, "UNDIROM %p has bad PXE ROM ID signature "
55                        "%08lx\n", undirom, undi_rom_id.Signature );
56                 return -EINVAL;
57         }
58
59         /* Check for UNDI loader */
60         undiloader = undi_rom_id.UNDILoader;
61         if ( ! undiloader ) {
62                 DBGC ( undirom, "UNDIROM %p has no UNDI loader\n", undirom );
63                 return -EINVAL;
64         }
65
66         /* Fill in UNDI ROM loader fields */
67         undirom->loader_entry.segment = undirom->rom_segment;
68         undirom->loader_entry.offset = undiloader;
69         undirom->code_size = undi_rom_id.CodeSize;
70         undirom->data_size = undi_rom_id.DataSize;
71
72         DBGC ( undirom, "UNDIROM %p has UNDI loader at %04x:%04x "
73                "(code %04x data %04x)\n", undirom,
74                undirom->loader_entry.segment, undirom->loader_entry.offset,
75                undirom->code_size, undirom->data_size );
76         return 0;
77 }
78
79 /**
80  * Parse PCI expansion header
81  *
82  * @v undirom           UNDI ROM
83  * @v pcirheader        Offset within ROM to PCI expansion header
84  */
85 static int undirom_parse_pcirheader ( struct undi_rom *undirom,
86                                      unsigned int pcirheader ) {
87         struct pcir_header pcir_header;
88
89         DBGC ( undirom, "UNDIROM %p has PCI expansion header at %04x:%04x\n",
90                undirom, undirom->rom_segment, pcirheader );
91
92         /* Read PCI expansion header and verify */
93         copy_from_real ( &pcir_header, undirom->rom_segment, pcirheader,
94                          sizeof ( pcir_header ) );
95         if ( pcir_header.signature != PCIR_SIGNATURE ) {
96                 DBGC ( undirom, "UNDIROM %p has bad PCI expansion header "
97                        "signature %08lx\n", undirom, pcir_header.signature );
98                 return -EINVAL;
99         }
100
101         /* Fill in UNDI ROM PCI device fields */
102         undirom->bus_type = PCI_NIC;
103         undirom->bus_id.pci.vendor_id = pcir_header.vendor_id;
104         undirom->bus_id.pci.device_id = pcir_header.device_id;
105
106         DBGC ( undirom, "UNDIROM %p is for PCI devices %04x:%04x\n", undirom,
107                undirom->bus_id.pci.vendor_id, undirom->bus_id.pci.device_id );
108         return 0;
109         
110 }
111
112 /**
113  * Probe UNDI ROM
114  *
115  * @v rom_segment       ROM segment address
116  * @ret rc              Return status code
117  */
118 static int undirom_probe ( unsigned int rom_segment ) {
119         struct undi_rom *undirom = NULL;
120         struct undi_rom_header romheader;
121         size_t rom_len;
122         unsigned int pxeromid;
123         unsigned int pcirheader;
124         int rc;
125
126         /* Read expansion ROM header and verify */
127         copy_from_real ( &romheader, rom_segment, 0, sizeof ( romheader ) );
128         if ( romheader.Signature != ROM_SIGNATURE ) {
129                 rc = -EINVAL;
130                 goto err;
131         }
132         rom_len = ( romheader.ROMLength * 512 );
133
134         /* Allocate memory for UNDI ROM */
135         undirom = malloc ( sizeof ( *undirom ) );
136         if ( ! undirom ) {
137                 DBG ( "Could not allocate UNDI ROM structure\n" );
138                 rc = -ENOMEM;
139                 goto err;
140         }
141         memset ( undirom, 0, sizeof ( *undirom ) );
142         DBGC ( undirom, "UNDIROM %p trying expansion ROM at %04x:0000 "
143                "(%zdkB)\n", undirom, rom_segment, ( rom_len / 1024 ) );
144         undirom->rom_segment = rom_segment;
145
146         /* Check for and parse PXE ROM ID */
147         pxeromid = romheader.PXEROMID;
148         if ( ! pxeromid ) {
149                 DBGC ( undirom, "UNDIROM %p has no PXE ROM ID\n", undirom );
150                 rc = -EINVAL;
151                 goto err;
152         }
153         if ( pxeromid > rom_len ) {
154                 DBGC ( undirom, "UNDIROM %p PXE ROM ID outside ROM\n",
155                        undirom );
156                 rc = -EINVAL;
157                 goto err;
158         }
159         if ( ( rc = undirom_parse_pxeromid ( undirom, pxeromid ) ) != 0 )
160                 goto err;
161
162         /* Parse PCIR header, if present */
163         pcirheader = romheader.PCIRHeader;
164         if ( pcirheader )
165                 undirom_parse_pcirheader ( undirom, pcirheader );
166
167         /* Add to UNDI ROM list and return */
168         DBGC ( undirom, "UNDIROM %p registered\n", undirom );
169         list_add ( &undirom->list, &undiroms );
170         return 0;
171
172  err:
173         free ( undirom );
174         return rc;
175 }
176
177 /**
178  * Create UNDI ROMs for all possible expansion ROMs
179  *
180  * @ret 
181  */
182 static void undirom_probe_all_roms ( void ) {
183         static int probed = 0;
184         unsigned int rom_segment;
185
186         /* Perform probe only once */
187         if ( probed )
188                 return;
189
190         DBG ( "Scanning for PXE expansion ROMs\n" );
191
192         /* Scan through expansion ROM region at 2kB intervals */
193         for ( rom_segment = 0xc000 ; rom_segment < 0x10000 ;
194               rom_segment += 0x80 ) {
195                 undirom_probe ( rom_segment );
196         }
197
198         probed = 1;
199 }
200
201 /**
202  * Find UNDI ROM for PCI device
203  *
204  * @v vendor_id         PCI vendor ID
205  * @v device_id         PCI device ID
206  * @v rombase           ROM base address, or 0 for any
207  * @ret undirom         UNDI ROM, or NULL
208  */
209 struct undi_rom * undirom_find_pci ( unsigned int vendor_id,
210                                      unsigned int device_id,
211                                      unsigned int rombase ) {
212         struct undi_rom *undirom;
213
214         undirom_probe_all_roms();
215
216         list_for_each_entry ( undirom, &undiroms, list ) {
217                 if ( undirom->bus_type != PCI_NIC )
218                         continue;
219                 if ( undirom->bus_id.pci.vendor_id != vendor_id )
220                         continue;
221                 if ( undirom->bus_id.pci.device_id != device_id )
222                         continue;
223                 if ( rombase && ( ( undirom->rom_segment << 4 ) != rombase ) )
224                         continue;
225                 DBGC ( undirom, "UNDIROM %p matched PCI %04x:%04x (%08x)\n",
226                        undirom, vendor_id, device_id, rombase );
227                 return undirom;
228         }
229
230         DBG ( "No UNDI ROM matched PCI %04x:%04x (%08x)\n",
231               vendor_id, device_id, rombase );
232         return NULL;
233 }