iPXE
pnic.c
Go to the documentation of this file.
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 
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 */
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;
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  }
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 ***************************************************************************/
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 
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;
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 */
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 
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 };
u16 length
Definition: sky2.h:9
iPXE I/O API
struct arbelprm_rc_send_wqe rc
Definition: arbel.h:14
unsigned short uint16_t
Definition: stdint.h:11
static void netdev_tx_complete(struct net_device *netdev, struct io_buffer *iobuf)
Complete network transmission.
Definition: netdevice.h:752
#define iob_put(iobuf, len)
Definition: iobuf.h:120
void netdev_rx_err(struct net_device *netdev, struct io_buffer *iobuf, int rc)
Discard received packet.
Definition: netdevice.c:586
int printf(const char *fmt,...)
Write a formatted string to the console.
Definition: vsprintf.c:464
uint16_t inw(volatile uint16_t *io_addr)
Read 16-bit word from I/O-mapped device.
A PCI driver.
Definition: pci.h:247
#define PNIC_CMD_MASK_IRQ
Definition: pnic_api.h:45
int(* open)(struct net_device *netdev)
Open network device.
Definition: netdevice.h:222
#define outw(data, io_addr)
Definition: io.h:319
Definition: pnic.c:39
unsigned long ioaddr
I/O address.
Definition: pci.h:221
Error codes.
#define PNIC_CMD_READ_MAC
Definition: pnic_api.h:40
A command-line command.
Definition: command.h:9
I/O buffers.
struct pci_device_id * ids
PCI ID table.
Definition: pci.h:249
static void pnic_poll(struct net_device *netdev)
Definition: pnic.c:127
Definition: bnxt_hsi.h:68
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 int pnic_transmit(struct net_device *netdev, struct io_buffer *iobuf)
Definition: pnic.c:161
void insb(volatile uint8_t *io_addr, uint8_t *data, unsigned int count)
Read bytes from I/O-mapped device.
unsigned short ioaddr
Definition: pnic.c:40
void adjust_pci_device(struct pci_device *pci)
Enable PCI device.
Definition: pci.c:154
struct io_buffer * alloc_iob(size_t len)
Allocate I/O buffer.
Definition: iobuf.c:129
struct device dev
Generic device.
Definition: pci.h:208
static void pnic_close(struct net_device *netdev __unused)
Definition: pnic.c:186
uint8_t status
Status.
Definition: ena.h:16
static void netdev_init(struct net_device *netdev, struct net_device_operations *op)
Initialise a network device.
Definition: netdevice.h:515
static void pnic_remove(struct pci_device *pci)
Definition: pnic.c:215
static void pci_set_drvdata(struct pci_device *pci, void *priv)
Set PCI driver-private data.
Definition: pci.h:359
#define ENOMEM
Not enough space.
Definition: errno.h:534
static struct pci_device_id pnic_nics[]
Definition: pnic.c:280
static void netdev_put(struct net_device *netdev)
Drop reference to network device.
Definition: netdevice.h:572
Ethernet protocol.
#define ETH_FRAME_LEN
Definition: if_ether.h:11
void * priv
Driver private data.
Definition: netdevice.h:431
static void netdev_link_up(struct net_device *netdev)
Mark network device as having link up.
Definition: netdevice.h:774
#define PNIC_STATUS_OK
Definition: pnic_api.h:54
#define PNIC_CMD_RECV
Definition: pnic_api.h:43
static struct net_device * netdev
Definition: gdbudp.c:52
#define PNIC_CMD_XMIT
Definition: pnic_api.h:42
#define PNIC_CMD_RESET
Definition: pnic_api.h:41
#define PNIC_API_VERSION
Definition: pnic_api.h:61
void unregister_netdev(struct net_device *netdev)
Unregister network device.
Definition: netdevice.c:941
#define PNIC_CMD_RECV_QLEN
Definition: pnic_api.h:44
PCI bus.
A PCI device.
Definition: pci.h:206
int register_netdev(struct net_device *netdev)
Register network device.
Definition: netdevice.c:759
static size_t iob_len(struct io_buffer *iobuf)
Calculate length of data in an I/O buffer.
Definition: iobuf.h:155
A network device.
Definition: netdevice.h:352
static void netdev_nullify(struct net_device *netdev)
Stop using a network device.
Definition: netdevice.h:528
unsigned char uint8_t
Definition: stdint.h:10
#define ETH_ALEN
Definition: if_ether.h:8
#define ETH_ZLEN
Definition: if_ether.h:10
A PCI device ID list entry.
Definition: pci.h:170
static struct xen_remove_from_physmap * remove
Definition: xenmem.h:39
struct pci_driver pnic_driver __pci_driver
Definition: pnic.c:285
Network device operations.
Definition: netdevice.h:213
void netdev_rx(struct net_device *netdev, struct io_buffer *iobuf)
Add packet to receive queue.
Definition: netdevice.c:548
struct device * dev
Underlying hardware device.
Definition: netdevice.h:364
#define PNIC_REG_STAT
Definition: pnic_api.h:27
Network device management.
#define __unused
Declare a variable or data structure as unused.
Definition: compiler.h:573
static void * pci_get_drvdata(struct pci_device *pci)
Get PCI driver-private data.
Definition: pci.h:369
void outsb(volatile uint8_t *io_addr, const uint8_t *data, unsigned int count)
Write bytes to I/O-mapped device.
static int pnic_api_check(uint16_t api_version)
Definition: pnic.c:111
#define PNIC_REG_DATA
Definition: pnic_api.h:29
#define PNIC_REG_LEN
Definition: pnic_api.h:28
int(* probe)(struct pci_device *pci)
Probe device.
Definition: pci.h:260
void * data
Start of data.
Definition: iobuf.h:48
#define EIO
Input/output error.
Definition: errno.h:433
static void pnic_irq(struct net_device *netdev, int enable)
Definition: pnic.c:193
struct net_device * alloc_etherdev(size_t priv_size)
Allocate Ethernet device.
Definition: ethernet.c:264
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
#define PNIC_REG_CMD
Definition: pnic_api.h:26
static int pnic_probe(struct pci_device *pci)
Definition: pnic.c:228
#define PNIC_CMD_API_VER
Definition: pnic_api.h:39
FILE_LICENCE(GPL2_OR_LATER)
static struct net_device_operations pnic_operations
Definition: pnic.c:204
#define DBG(...)
Print a debugging message.
Definition: compiler.h:498
uint8_t hw_addr[MAX_HW_ADDR_LEN]
Hardware address.
Definition: netdevice.h:381
#define NULL
NULL pointer (VOID *)
Definition: Base.h:321
static int pnic_open(struct net_device *netdev __unused)
Definition: pnic.c:178
#define PCI_ROM(_vendor, _device, _name, _description, _data)
Definition: pci.h:303
void iob_pad(struct io_buffer *iobuf, size_t min_len)
Pad I/O buffer.
Definition: iobpad.c:49
A persistent I/O buffer.
Definition: iobuf.h:33