iPXE
pnic.c
Go to the documentation of this file.
1/**************************************************************************
2Etherboot - BOOTP/TFTP Bootstrap Program
3Bochs 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
25FILE_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
39struct 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
56 const void *input, uint16_t input_length,
57 void *output, uint16_t output_max_length,
58 uint16_t *output_length ) {
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 */
70 /* Retrieve status */
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
97 const void *input, uint16_t input_length,
98 void *output, uint16_t output_max_length,
99 uint16_t *output_length ) {
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 */
111static 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/**************************************************************************
125POLL - Wait for a frame
126***************************************************************************/
127static void pnic_poll ( struct net_device *netdev ) {
128 struct pnic *pnic = netdev->priv;
129 struct io_buffer *iobuf;
131 uint16_t qlen;
132
133 /* Fetch all available packets */
134 while ( 1 ) {
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" );
145 return;
146 }
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/**************************************************************************
159TRANSMIT - Transmit a frame
160***************************************************************************/
161static 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/**************************************************************************
176OPEN - Open network device
177***************************************************************************/
178static int pnic_open ( struct net_device *netdev __unused ) {
179 /* Nothing to do */
180 return 0;
181}
182
183/**************************************************************************
184CLOSE - Close network device
185***************************************************************************/
186static void pnic_close ( struct net_device *netdev __unused ) {
187 /* Nothing to do */
188}
189
190/**************************************************************************
191IRQ - Enable/disable interrupts
192***************************************************************************/
193static 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/**************************************************************************
202OPERATIONS TABLE
203***************************************************************************/
205 .open = pnic_open,
206 .close = pnic_close,
207 .transmit = pnic_transmit,
208 .poll = pnic_poll,
209 .irq = pnic_irq,
210};
211
212/**************************************************************************
213DISABLE - Turn off ethernet interface
214***************************************************************************/
215static void pnic_remove ( struct pci_device *pci ) {
216 struct net_device *netdev = pci_get_drvdata ( pci );
217 struct pnic *pnic = netdev->priv;
218
222 netdev_put ( netdev );
223}
224
225/**************************************************************************
226PROBE - Look for an adapter, this routine's visible to the outside
227***************************************************************************/
228static int pnic_probe ( struct pci_device *pci ) {
229 struct net_device *netdev;
230 struct pnic *pnic;
231 uint16_t api_version;
233 int rc;
234
235 /* Allocate net device */
236 netdev = alloc_etherdev ( sizeof ( *pnic ) );
237 if ( ! netdev )
238 return -ENOMEM;
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 */
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 */
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 */
270
271 return 0;
272
273 err:
274 /* Free net device */
276 netdev_put ( netdev );
277 return rc;
278}
279
280static struct pci_device_id pnic_nics[] = {
281/* genrules.pl doesn't let us use macros for PCI IDs...*/
282PCI_ROM ( 0xfefe, 0xefef, "pnic", "Bochs Pseudo NIC Adaptor", 0 ),
283};
284
285struct pci_driver pnic_driver __pci_driver = {
286 .ids = pnic_nics,
287 .id_count = ( sizeof ( pnic_nics ) / sizeof ( pnic_nics[0] ) ),
288 .probe = pnic_probe,
290};
#define NULL
NULL pointer (VOID *)
Definition Base.h:322
struct arbelprm_rc_send_wqe rc
Definition arbel.h:3
unsigned short uint16_t
Definition stdint.h:11
unsigned char uint8_t
Definition stdint.h:10
uint8_t status
Status.
Definition ena.h:5
Error codes.
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Definition ethernet.c:265
Ethernet protocol.
static struct net_device * netdev
Definition gdbudp.c:53
#define __unused
Declare a variable or data structure as unused.
Definition compiler.h:573
#define DBG(...)
Print a debugging message.
Definition compiler.h:498
#define FILE_LICENCE(_licence)
Declare a particular licence as applying to a file.
Definition compiler.h:896
#define ENOMEM
Not enough space.
Definition errno.h:535
#define EIO
Input/output error.
Definition errno.h:434
#define ETH_ZLEN
Definition if_ether.h:11
#define ETH_FRAME_LEN
Definition if_ether.h:12
#define ETH_ALEN
Definition if_ether.h:9
iPXE I/O API
#define inw(io_addr)
Definition io.h:292
#define outw(data, io_addr)
Definition io.h:320
#define insb(io_addr, data, count)
Definition io.h:401
#define outsb(io_addr, data, count)
Definition io.h:435
void iob_pad(struct io_buffer *iobuf, size_t min_len)
Pad I/O buffer.
Definition iobpad.c:50
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition iobuf.c:131
I/O buffers.
#define iob_put(iobuf, len)
Definition iobuf.h:125
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition iobuf.h:160
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
Definition netdevice.c:549
void unregister_netdev(struct net_device *netdev)
Unregister network device.
Definition netdevice.c:942
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
Definition netdevice.c:587
int register_netdev(struct net_device *netdev)
Register network device.
Definition netdevice.c:760
Network device management.
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
Definition netdevice.h:789
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
Definition netdevice.h:519
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
Definition netdevice.h:532
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition netdevice.h:576
static void netdev_tx_complete(struct net_device *netdev, struct io_buffer *iobuf)
Complete network transmission.
Definition netdevice.h:767
void adjust_pci_device(struct pci_device *pci)
Enable PCI device.
Definition pci.c:241
PCI bus.
#define __pci_driver
Declare a PCI driver.
Definition pci.h:278
static void pci_set_drvdata(struct pci_device *pci, void *priv)
Set PCI driver-private data.
Definition pci.h:366
#define PCI_ROM(_vendor, _device, _name, _description, _data)
Definition pci.h:308
static void * pci_get_drvdata(struct pci_device *pci)
Get PCI driver-private data.
Definition pci.h:376
static int pnic_probe(struct pci_device *pci)
Definition pnic.c:228
static uint16_t pnic_command(struct pnic *pnic, uint16_t command, const void *input, uint16_t input_length, void *output, uint16_t output_max_length, uint16_t *output_length)
Definition pnic.c:96
static int pnic_open(struct net_device *netdev __unused)
Definition pnic.c:178
static void pnic_irq(struct net_device *netdev, int enable)
Definition pnic.c:193
static struct net_device_operations pnic_operations
Definition pnic.c:204
static void pnic_poll(struct net_device *netdev)
Definition pnic.c:127
static struct pci_device_id pnic_nics[]
Definition pnic.c:280
static int pnic_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Definition pnic.c:161
static void pnic_close(struct net_device *netdev __unused)
Definition pnic.c:186
static uint16_t pnic_command_quiet(struct pnic *pnic, uint16_t command, const void *input, uint16_t input_length, void *output, uint16_t output_max_length, uint16_t *output_length)
Definition pnic.c:55
static void pnic_remove(struct pci_device *pci)
Definition pnic.c:215
static int pnic_api_check(uint16_t api_version)
Definition pnic.c:111
#define PNIC_CMD_RESET
Definition pnic_api.h:41
#define PNIC_CMD_API_VER
Definition pnic_api.h:39
#define PNIC_API_VERSION
Definition pnic_api.h:61
#define PNIC_CMD_RECV_QLEN
Definition pnic_api.h:44
#define PNIC_CMD_MASK_IRQ
Definition pnic_api.h:45
#define PNIC_REG_CMD
Definition pnic_api.h:26
#define PNIC_REG_DATA
Definition pnic_api.h:29
#define PNIC_CMD_XMIT
Definition pnic_api.h:42
#define PNIC_CMD_RECV
Definition pnic_api.h:43
#define PNIC_REG_STAT
Definition pnic_api.h:27
#define PNIC_REG_LEN
Definition pnic_api.h:28
#define PNIC_STATUS_OK
Definition pnic_api.h:54
#define PNIC_CMD_READ_MAC
Definition pnic_api.h:40
u16 length
Definition sky2.h:1
A command-line command.
Definition command.h:10
A persistent I/O buffer.
Definition iobuf.h:38
void * data
Start of data.
Definition iobuf.h:53
Network device operations.
Definition netdevice.h:214
A network device.
Definition netdevice.h:353
A PCI device ID list entry.
Definition pci.h:175
A PCI device.
Definition pci.h:211
unsigned long ioaddr
I/O address.
Definition pci.h:226
struct device dev
Generic device.
Definition pci.h:213
A PCI driver.
Definition pci.h:252
int(* probe)(struct pci_device *pci)
Probe device.
Definition pci.h:265
Definition pnic.c:39
unsigned short ioaddr
Definition pnic.c:40
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition vsprintf.c:465
static struct xen_remove_from_physmap * remove
Definition xenmem.h:40