[intel] Forcibly skip PHY reset on some models
[ipxe.git] / src / core / downloader.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., 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 <stdlib.h>
27 #include <errno.h>
28 #include <syslog.h>
29 #include <ipxe/iobuf.h>
30 #include <ipxe/xfer.h>
31 #include <ipxe/open.h>
32 #include <ipxe/job.h>
33 #include <ipxe/uaccess.h>
34 #include <ipxe/umalloc.h>
35 #include <ipxe/image.h>
36 #include <ipxe/xferbuf.h>
37 #include <ipxe/downloader.h>
38
39 /** @file
40 *
41 * Image downloader
42 *
43 */
44
45 /** A downloader */
46 struct downloader {
47 /** Reference count for this object */
48 struct refcnt refcnt;
49
50 /** Job control interface */
51 struct interface job;
52 /** Data transfer interface */
53 struct interface xfer;
54
55 /** Image to contain downloaded file */
56 struct image *image;
57 /** Data transfer buffer */
58 struct xfer_buffer buffer;
59 };
60
61 /**
62 * Free downloader object
63 *
64 * @v refcnt Downloader reference counter
65 */
66 static void downloader_free ( struct refcnt *refcnt ) {
67 struct downloader *downloader =
68 container_of ( refcnt, struct downloader, refcnt );
69
70 image_put ( downloader->image );
71 free ( downloader );
72 }
73
74 /**
75 * Terminate download
76 *
77 * @v downloader Downloader
78 * @v rc Reason for termination
79 */
80 static void downloader_finished ( struct downloader *downloader, int rc ) {
81
82 /* Log download status */
83 if ( rc == 0 ) {
84 syslog ( LOG_NOTICE, "Downloaded \"%s\"\n",
85 downloader->image->name );
86 } else {
87 syslog ( LOG_ERR, "Download of \"%s\" failed: %s\n",
88 downloader->image->name, strerror ( rc ) );
89 }
90
91 /* Update image length */
92 downloader->image->len = downloader->buffer.len;
93
94 /* Shut down interfaces */
95 intf_shutdown ( &downloader->xfer, rc );
96 intf_shutdown ( &downloader->job, rc );
97 }
98
99 /****************************************************************************
100 *
101 * Job control interface
102 *
103 */
104
105 /**
106 * Report progress of download job
107 *
108 * @v downloader Downloader
109 * @v progress Progress report to fill in
110 * @ret ongoing_rc Ongoing job status code (if known)
111 */
112 static int downloader_progress ( struct downloader *downloader,
113 struct job_progress *progress ) {
114
115 /* This is not entirely accurate, since downloaded data may
116 * arrive out of order (e.g. with multicast protocols), but
117 * it's a reasonable first approximation.
118 */
119 progress->completed = downloader->buffer.pos;
120 progress->total = downloader->buffer.len;
121
122 return 0;
123 }
124
125 /****************************************************************************
126 *
127 * Data transfer interface
128 *
129 */
130
131 /**
132 * Handle received data
133 *
134 * @v downloader Downloader
135 * @v iobuf Datagram I/O buffer
136 * @v meta Data transfer metadata
137 * @ret rc Return status code
138 */
139 static int downloader_xfer_deliver ( struct downloader *downloader,
140 struct io_buffer *iobuf,
141 struct xfer_metadata *meta ) {
142 int rc;
143
144 /* Add data to buffer */
145 if ( ( rc = xferbuf_deliver ( &downloader->buffer, iob_disown ( iobuf ),
146 meta ) ) != 0 )
147 goto err_deliver;
148
149 return 0;
150
151 err_deliver:
152 downloader_finished ( downloader, rc );
153 return rc;
154 }
155
156 /**
157 * Get underlying data transfer buffer
158 *
159 * @v downloader Downloader
160 * @ret xferbuf Data transfer buffer, or NULL on error
161 */
162 static struct xfer_buffer *
163 downloader_xfer_buffer ( struct downloader *downloader ) {
164
165 /* Provide direct access to underlying data transfer buffer */
166 return &downloader->buffer;
167 }
168
169 /** Downloader data transfer interface operations */
170 static struct interface_operation downloader_xfer_operations[] = {
171 INTF_OP ( xfer_deliver, struct downloader *, downloader_xfer_deliver ),
172 INTF_OP ( xfer_buffer, struct downloader *, downloader_xfer_buffer ),
173 INTF_OP ( intf_close, struct downloader *, downloader_finished ),
174 };
175
176 /** Downloader data transfer interface descriptor */
177 static struct interface_descriptor downloader_xfer_desc =
178 INTF_DESC ( struct downloader, xfer, downloader_xfer_operations );
179
180 /****************************************************************************
181 *
182 * Job control interface
183 *
184 */
185
186 /** Downloader job control interface operations */
187 static struct interface_operation downloader_job_op[] = {
188 INTF_OP ( job_progress, struct downloader *, downloader_progress ),
189 INTF_OP ( intf_close, struct downloader *, downloader_finished ),
190 };
191
192 /** Downloader job control interface descriptor */
193 static struct interface_descriptor downloader_job_desc =
194 INTF_DESC ( struct downloader, job, downloader_job_op );
195
196 /****************************************************************************
197 *
198 * Instantiator
199 *
200 */
201
202 /**
203 * Instantiate a downloader
204 *
205 * @v job Job control interface
206 * @v image Image to fill with downloaded file
207 * @ret rc Return status code
208 *
209 * Instantiates a downloader object to download the content of the
210 * specified image from its URI.
211 */
212 int create_downloader ( struct interface *job, struct image *image ) {
213 struct downloader *downloader;
214 int rc;
215
216 /* Allocate and initialise structure */
217 downloader = zalloc ( sizeof ( *downloader ) );
218 if ( ! downloader )
219 return -ENOMEM;
220 ref_init ( &downloader->refcnt, downloader_free );
221 intf_init ( &downloader->job, &downloader_job_desc,
222 &downloader->refcnt );
223 intf_init ( &downloader->xfer, &downloader_xfer_desc,
224 &downloader->refcnt );
225 downloader->image = image_get ( image );
226 xferbuf_umalloc_init ( &downloader->buffer, &image->data );
227
228 /* Instantiate child objects and attach to our interfaces */
229 if ( ( rc = xfer_open_uri ( &downloader->xfer, image->uri ) ) != 0 )
230 goto err;
231
232 /* Attach parent interface, mortalise self, and return */
233 intf_plug_plug ( &downloader->job, job );
234 ref_put ( &downloader->refcnt );
235 return 0;
236
237 err:
238 downloader_finished ( downloader, rc );
239 ref_put ( &downloader->refcnt );
240 return rc;
241 }