]> git.proxmox.com Git - grub2.git/blob - debian/grub-extras/disabled/gpxe/src/drivers/net/pnic.c
grub2 (2.02+dfsg1-20) unstable; urgency=medium
[grub2.git] / debian / grub-extras / disabled / gpxe / 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 <gpxe/io.h>
20 #include <errno.h>
21 #include <gpxe/pci.h>
22 #include <gpxe/if_ether.h>
23 #include <gpxe/ethernet.h>
24 #include <gpxe/iobuf.h>
25 #include <gpxe/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 const struct pci_device_id *id __unused ) {
220 struct net_device *netdev;
221 struct pnic *pnic;
222 uint16_t api_version;
223 uint16_t status;
224 int rc;
225
226 /* Allocate net device */
227 netdev = alloc_etherdev ( sizeof ( *pnic ) );
228 if ( ! netdev )
229 return -ENOMEM;
230 netdev_init ( netdev, &pnic_operations );
231 pnic = netdev->priv;
232 pci_set_drvdata ( pci, netdev );
233 netdev->dev = &pci->dev;
234 pnic->ioaddr = pci->ioaddr;
235
236 /* Fix up PCI device */
237 adjust_pci_device ( pci );
238
239 /* API version check */
240 status = pnic_command_quiet ( pnic, PNIC_CMD_API_VER, NULL, 0,
241 &api_version,
242 sizeof ( api_version ), NULL );
243 if ( status != PNIC_STATUS_OK ) {
244 printf ( "PNIC failed installation check, code %#hx\n",
245 status );
246 rc = -EIO;
247 goto err;
248 }
249 pnic_api_check ( api_version );
250
251 /* Get MAC address */
252 status = pnic_command ( pnic, PNIC_CMD_READ_MAC, NULL, 0,
253 netdev->hw_addr, ETH_ALEN, NULL );
254
255 /* Mark as link up; PNIC has no concept of link state */
256 netdev_link_up ( netdev );
257
258 /* Register network device */
259 if ( ( rc = register_netdev ( netdev ) ) != 0 )
260 goto err;
261
262 return 0;
263
264 err:
265 /* Free net device */
266 netdev_nullify ( netdev );
267 netdev_put ( netdev );
268 return rc;
269 }
270
271 static struct pci_device_id pnic_nics[] = {
272 /* genrules.pl doesn't let us use macros for PCI IDs...*/
273 PCI_ROM ( 0xfefe, 0xefef, "pnic", "Bochs Pseudo NIC Adaptor", 0 ),
274 };
275
276 struct pci_driver pnic_driver __pci_driver = {
277 .ids = pnic_nics,
278 .id_count = ( sizeof ( pnic_nics ) / sizeof ( pnic_nics[0] ) ),
279 .probe = pnic_probe,
280 .remove = pnic_remove,
281 };