These changes are the raw update to qemu-2.6.
[kvmfornfv.git] / qemu / roms / ipxe / src / drivers / net / pnic.c
1 /**************************************************************************
2 Etherboot -  BOOTP/TFTP Bootstrap Program
3 Bochs Pseudo NIC driver for Etherboot
4 ***************************************************************************/
5
6 /*
7  * This program is free software; you can redistribute it and/or
8  * modify it under the terms of the GNU General Public License as
9  * published by the Free Software Foundation; either version 2 of the
10  * License, or (at your option) any later version.
11  *
12  * This program is distributed in the hope that it will be useful, but
13  * WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * General Public License for more details.
16  *
17  * You should have received a copy of the GNU General Public License
18  * along with this program; if not, write to the Free Software
19  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA
20  * 02110-1301, USA.
21  *
22  * See pnic_api.h for an explanation of the Bochs Pseudo NIC.
23  */
24
25 FILE_LICENCE ( GPL2_OR_LATER );
26
27 #include <stdint.h>
28 #include <stdio.h>
29 #include <ipxe/io.h>
30 #include <errno.h>
31 #include <ipxe/pci.h>
32 #include <ipxe/if_ether.h>
33 #include <ipxe/ethernet.h>
34 #include <ipxe/iobuf.h>
35 #include <ipxe/netdevice.h>
36
37 #include "pnic_api.h"
38
39 struct pnic {
40         unsigned short ioaddr;
41 };
42
43 /* 
44  * Utility functions: issue a PNIC command, retrieve result.  Use
45  * pnic_command_quiet if you don't want failure codes to be
46  * automatically printed.  Returns the PNIC status code.
47  * 
48  * Set output_length to NULL only if you expect to receive exactly
49  * output_max_length bytes, otherwise it'll complain that you didn't
50  * get enough data (on the assumption that if you not interested in
51  * discovering the output length then you're expecting a fixed amount
52  * of data).
53  */
54
55 static uint16_t pnic_command_quiet ( struct pnic *pnic, uint16_t command,
56                                      const void *input, uint16_t input_length,
57                                      void *output, uint16_t output_max_length,
58                                      uint16_t *output_length ) {
59         uint16_t status;
60         uint16_t _output_length;
61
62         if ( input != NULL ) {
63                 /* Write input length */
64                 outw ( input_length, pnic->ioaddr + PNIC_REG_LEN );
65                 /* Write input data */
66                 outsb ( pnic->ioaddr + PNIC_REG_DATA, input, input_length );
67         }
68         /* Write command */
69         outw ( command, pnic->ioaddr + PNIC_REG_CMD );
70         /* Retrieve status */
71         status = inw ( pnic->ioaddr + PNIC_REG_STAT );
72         /* Retrieve output length */
73         _output_length = inw ( pnic->ioaddr + PNIC_REG_LEN );
74         if ( output_length == NULL ) {
75                 if ( _output_length != output_max_length ) {
76                         printf ( "pnic_command %#hx: wrong data length "
77                                  "returned (expected %d, got %d)\n", command,
78                                  output_max_length, _output_length );
79                 }
80         } else {
81                 *output_length = _output_length;
82         }
83         if ( output != NULL ) {
84                 if ( _output_length > output_max_length ) {
85                         printf ( "pnic_command %#hx: output buffer too small "
86                                  "(have %d, need %d)\n", command,
87                                  output_max_length, _output_length );
88                         _output_length = output_max_length;
89                 }
90                 /* Retrieve output data */
91                 insb ( pnic->ioaddr + PNIC_REG_DATA, output, _output_length );
92         }
93         return status;
94 }
95
96 static uint16_t pnic_command ( struct pnic *pnic, uint16_t command,
97                                const void *input, uint16_t input_length,
98                                void *output, uint16_t output_max_length,
99                                uint16_t *output_length ) {
100         uint16_t status = pnic_command_quiet ( pnic, command,
101                                                input, input_length,
102                                                output, output_max_length,
103                                                output_length );
104         if ( status == PNIC_STATUS_OK ) return status;
105         printf ( "PNIC command %#hx (len %#hx) failed with status %#hx\n",
106                  command, input_length, status );
107         return status;
108 }
109
110 /* Check API version matches that of NIC */
111 static int pnic_api_check ( uint16_t api_version ) {
112         if ( api_version != PNIC_API_VERSION ) {
113                 printf ( "Warning: API version mismatch! "
114                          "(NIC's is %d.%d, ours is %d.%d)\n",
115                          api_version >> 8, api_version & 0xff,
116                          PNIC_API_VERSION >> 8, PNIC_API_VERSION & 0xff );
117         }
118         if ( api_version < PNIC_API_VERSION ) {
119                 printf ( "** You may need to update your copy of Bochs **\n" );
120         }
121         return ( api_version == PNIC_API_VERSION );
122 }
123
124 /**************************************************************************
125 POLL - Wait for a frame
126 ***************************************************************************/
127 static void pnic_poll ( struct net_device *netdev ) {
128         struct pnic *pnic = netdev->priv;
129         struct io_buffer *iobuf;
130         uint16_t length;
131         uint16_t qlen;
132
133         /* Fetch all available packets */
134         while ( 1 ) {
135                 if ( pnic_command ( pnic, PNIC_CMD_RECV_QLEN, NULL, 0,
136                                     &qlen, sizeof ( qlen ), NULL )
137                      != PNIC_STATUS_OK )
138                         return;
139                 if ( qlen == 0 )
140                         return;
141                 iobuf = alloc_iob ( ETH_FRAME_LEN );
142                 if ( ! iobuf ) {
143                         DBG ( "could not allocate buffer\n" );
144                         netdev_rx_err ( netdev, NULL, -ENOMEM );
145                         return;
146                 }
147                 if ( pnic_command ( pnic, PNIC_CMD_RECV, NULL, 0,
148                                     iobuf->data, ETH_FRAME_LEN, &length )
149                      != PNIC_STATUS_OK ) {
150                         netdev_rx_err ( netdev, iobuf, -EIO );
151                         return;
152                 }
153                 iob_put ( iobuf, length );
154                 netdev_rx ( netdev, iobuf );
155         }
156 }
157
158 /**************************************************************************
159 TRANSMIT - Transmit a frame
160 ***************************************************************************/
161 static int pnic_transmit ( struct net_device *netdev, struct io_buffer *iobuf ) {
162         struct pnic *pnic = netdev->priv;
163
164         /* Pad the packet */
165         iob_pad ( iobuf, ETH_ZLEN );
166
167         /* Send packet */
168         pnic_command ( pnic, PNIC_CMD_XMIT, iobuf->data, iob_len ( iobuf ),
169                        NULL, 0, NULL );
170
171         netdev_tx_complete ( netdev, iobuf );
172         return 0;
173 }
174
175 /**************************************************************************
176 OPEN - Open network device
177 ***************************************************************************/
178 static int pnic_open ( struct net_device *netdev __unused ) {
179         /* Nothing to do */
180         return 0;
181 }
182
183 /**************************************************************************
184 CLOSE - Close network device
185 ***************************************************************************/
186 static void pnic_close ( struct net_device *netdev __unused ) {
187         /* Nothing to do */
188 }
189
190 /**************************************************************************
191 IRQ - Enable/disable interrupts
192 ***************************************************************************/
193 static void pnic_irq ( struct net_device *netdev, int enable ) {
194         struct pnic *pnic = netdev->priv;
195         uint8_t mask = ( enable ? 1 : 0 );
196         
197         pnic_command ( pnic, PNIC_CMD_MASK_IRQ, &mask, sizeof ( mask ),
198                        NULL, 0, NULL );
199 }
200
201 /**************************************************************************
202 OPERATIONS TABLE
203 ***************************************************************************/
204 static struct net_device_operations pnic_operations = {
205         .open           = pnic_open,
206         .close          = pnic_close,
207         .transmit       = pnic_transmit,
208         .poll           = pnic_poll,
209         .irq            = pnic_irq,
210 };
211
212 /**************************************************************************
213 DISABLE - Turn off ethernet interface
214 ***************************************************************************/
215 static void pnic_remove ( struct pci_device *pci ) {
216         struct net_device *netdev = pci_get_drvdata ( pci );
217         struct pnic *pnic = netdev->priv;
218
219         unregister_netdev ( netdev );
220         pnic_command ( pnic, PNIC_CMD_RESET, NULL, 0, NULL, 0, NULL );
221         netdev_nullify ( netdev );
222         netdev_put ( netdev );
223 }
224
225 /**************************************************************************
226 PROBE - Look for an adapter, this routine's visible to the outside
227 ***************************************************************************/
228 static int pnic_probe ( struct pci_device *pci ) {
229         struct net_device *netdev;
230         struct pnic *pnic;
231         uint16_t api_version;
232         uint16_t status;
233         int rc;
234
235         /* Allocate net device */
236         netdev = alloc_etherdev ( sizeof ( *pnic ) );
237         if ( ! netdev )
238                 return -ENOMEM;
239         netdev_init ( netdev, &pnic_operations );
240         pnic = netdev->priv;
241         pci_set_drvdata ( pci, netdev );
242         netdev->dev = &pci->dev;
243         pnic->ioaddr = pci->ioaddr;
244
245         /* Fix up PCI device */
246         adjust_pci_device ( pci );
247         
248         /* API version check */
249         status = pnic_command_quiet ( pnic, PNIC_CMD_API_VER, NULL, 0,
250                                       &api_version,
251                                       sizeof ( api_version ), NULL );
252         if ( status != PNIC_STATUS_OK ) {
253                 printf ( "PNIC failed installation check, code %#hx\n",
254                          status );
255                 rc = -EIO;
256                 goto err;
257         }
258         pnic_api_check ( api_version );
259
260         /* Get MAC address */
261         status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0,
262                                 netdev->hw_addr, ETH_ALEN, NULL );
263
264         /* Register network device */
265         if ( ( rc = register_netdev ( netdev ) ) != 0 )
266                 goto err;
267
268         /* Mark as link up; PNIC has no concept of link state */
269         netdev_link_up ( netdev );
270
271         return 0;
272
273  err:
274         /* Free net device */
275         netdev_nullify ( netdev );
276         netdev_put ( netdev );
277         return rc;
278 }
279
280 static struct pci_device_id pnic_nics[] = {
281 /* genrules.pl doesn't let us use macros for PCI IDs...*/
282 PCI_ROM ( 0xfefe, 0xefef, "pnic", "Bochs Pseudo NIC Adaptor", 0 ),
283 };
284
285 struct pci_driver pnic_driver __pci_driver = {
286         .ids = pnic_nics,
287         .id_count = ( sizeof ( pnic_nics ) / sizeof ( pnic_nics[0] ) ),
288         .probe = pnic_probe,
289         .remove = pnic_remove,
290 };