|
|
1.1 root 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: };
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.