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