00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022 #include "etherboot.h"
00023 #include "nic.h"
00024 #include "gpxe/virtio-ring.h"
00025 #include "gpxe/virtio-pci.h"
00026 #include "virtio-net.h"
00027
00028 #define BUG() do { \
00029 printf("BUG: failure at %s:%d/%s()!\n", \
00030 __FILE__, __LINE__, __FUNCTION__); \
00031 while(1); \
00032 } while (0)
00033 #define BUG_ON(condition) do { if (condition) BUG(); } while (0)
00034
00035
00036
00037 struct eth_hdr {
00038 unsigned char dst_addr[ETH_ALEN];
00039 unsigned char src_addr[ETH_ALEN];
00040 unsigned short type;
00041 };
00042
00043 struct eth_frame {
00044 struct eth_hdr hdr;
00045 unsigned char data[ETH_FRAME_LEN];
00046 };
00047
00048
00049
00050 static struct virtio_net_hdr tx_virtio_hdr;
00051 static struct eth_frame tx_eth_frame;
00052
00053
00054
00055 #define RX_BUF_NB 6
00056 static struct virtio_net_hdr rx_hdr[RX_BUF_NB];
00057 static unsigned char rx_buffer[RX_BUF_NB][ETH_FRAME_LEN];
00058
00059
00060
00061 enum {
00062 RX_INDEX = 0,
00063 TX_INDEX,
00064 QUEUE_NB
00065 };
00066
00067 static struct vring_virtqueue virtqueue[QUEUE_NB];
00068
00069
00070
00071
00072
00073
00074
00075
00076 static void virtnet_disable(struct nic *nic)
00077 {
00078 int i;
00079
00080 for (i = 0; i < QUEUE_NB; i++) {
00081 vring_disable_cb(&virtqueue[i]);
00082 vp_del_vq(nic->ioaddr, i);
00083 }
00084 vp_reset(nic->ioaddr);
00085 }
00086
00087
00088
00089
00090
00091
00092
00093
00094
00095
00096
00097
00098 static int virtnet_poll(struct nic *nic, int retrieve)
00099 {
00100 unsigned int len;
00101 u16 token;
00102 struct virtio_net_hdr *hdr;
00103 struct vring_list list[2];
00104
00105 if (!vring_more_used(&virtqueue[RX_INDEX]))
00106 return 0;
00107
00108 if (!retrieve)
00109 return 1;
00110
00111 token = vring_get_buf(&virtqueue[RX_INDEX], &len);
00112
00113 BUG_ON(len > sizeof(struct virtio_net_hdr) + ETH_FRAME_LEN);
00114
00115 hdr = &rx_hdr[token];
00116 len -= sizeof(struct virtio_net_hdr);
00117
00118 nic->packetlen = len;
00119 memcpy(nic->packet, (char *)rx_buffer[token], nic->packetlen);
00120
00121
00122
00123 list[0].addr = (char*)&rx_hdr[token];
00124 list[0].length = sizeof(struct virtio_net_hdr);
00125 list[1].addr = (char*)&rx_buffer[token];
00126 list[1].length = ETH_FRAME_LEN;
00127
00128 vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, token, 0);
00129 vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], 1);
00130
00131 return 1;
00132 }
00133
00134
00135
00136
00137
00138
00139
00140
00141
00142 static void virtnet_transmit(struct nic *nic, const char *destaddr,
00143 unsigned int type, unsigned int len, const char *data)
00144 {
00145 struct vring_list list[2];
00146
00147
00148
00149
00150
00151
00152
00153
00154 tx_virtio_hdr.flags = 0;
00155 tx_virtio_hdr.csum_offset = 0;
00156 tx_virtio_hdr.csum_start = 0;
00157 tx_virtio_hdr.gso_type = VIRTIO_NET_HDR_GSO_NONE;
00158 tx_virtio_hdr.gso_size = 0;
00159 tx_virtio_hdr.hdr_len = 0;
00160
00161
00162
00163 BUG_ON(len > sizeof(tx_eth_frame.data));
00164
00165 memcpy(tx_eth_frame.hdr.dst_addr, destaddr, ETH_ALEN);
00166 memcpy(tx_eth_frame.hdr.src_addr, nic->node_addr, ETH_ALEN);
00167 tx_eth_frame.hdr.type = htons(type);
00168 memcpy(tx_eth_frame.data, data, len);
00169
00170 list[0].addr = (char*)&tx_virtio_hdr;
00171 list[0].length = sizeof(struct virtio_net_hdr);
00172 list[1].addr = (char*)&tx_eth_frame;
00173 list[1].length = ETH_FRAME_LEN;
00174
00175 vring_add_buf(&virtqueue[TX_INDEX], list, 2, 0, 0, 0);
00176
00177 vring_kick(nic->ioaddr, &virtqueue[TX_INDEX], 1);
00178
00179
00180
00181
00182
00183
00184
00185
00186 while (!vring_more_used(&virtqueue[TX_INDEX])) {
00187 mb();
00188 udelay(10);
00189 }
00190
00191
00192
00193 (void)vring_get_buf(&virtqueue[TX_INDEX], NULL);
00194 }
00195
00196 static void virtnet_irq(struct nic *nic __unused, irq_action_t action)
00197 {
00198 switch ( action ) {
00199 case DISABLE :
00200 vring_disable_cb(&virtqueue[RX_INDEX]);
00201 vring_disable_cb(&virtqueue[TX_INDEX]);
00202 break;
00203 case ENABLE :
00204 vring_enable_cb(&virtqueue[RX_INDEX]);
00205 vring_enable_cb(&virtqueue[TX_INDEX]);
00206 break;
00207 case FORCE :
00208 break;
00209 }
00210 }
00211
00212 static void provide_buffers(struct nic *nic)
00213 {
00214 int i;
00215 struct vring_list list[2];
00216
00217 for (i = 0; i < RX_BUF_NB; i++) {
00218 list[0].addr = (char*)&rx_hdr[i];
00219 list[0].length = sizeof(struct virtio_net_hdr);
00220 list[1].addr = (char*)&rx_buffer[i];
00221 list[1].length = ETH_FRAME_LEN;
00222 vring_add_buf(&virtqueue[RX_INDEX], list, 0, 2, i, i);
00223 }
00224
00225
00226
00227 vring_kick(nic->ioaddr, &virtqueue[RX_INDEX], i);
00228 }
00229
00230 static struct nic_operations virtnet_operations = {
00231 .connect = dummy_connect,
00232 .poll = virtnet_poll,
00233 .transmit = virtnet_transmit,
00234 .irq = virtnet_irq,
00235 };
00236
00237
00238
00239
00240
00241
00242
00243
00244 static int virtnet_probe(struct nic *nic, struct pci_device *pci)
00245 {
00246 u32 features;
00247 int i;
00248
00249
00250
00251 nic->ioaddr = pci->ioaddr & ~3;
00252
00253
00254
00255 nic->irqno = pci->irq;
00256
00257 printf("I/O address 0x%08x, IRQ #%d\n", nic->ioaddr, nic->irqno);
00258
00259 adjust_pci_device(pci);
00260
00261 vp_reset(nic->ioaddr);
00262
00263 features = vp_get_features(nic->ioaddr);
00264 if (features & (1 << VIRTIO_NET_F_MAC)) {
00265 vp_get(nic->ioaddr, offsetof(struct virtio_net_config, mac),
00266 nic->node_addr, ETH_ALEN);
00267 printf("MAC address ");
00268 for (i = 0; i < ETH_ALEN; i++) {
00269 printf("%02x%c", nic->node_addr[i],
00270 (i == ETH_ALEN - 1) ? '\n' : ':');
00271 }
00272 }
00273
00274
00275
00276 for (i = 0; i < QUEUE_NB; i++) {
00277 virtqueue[i].free_head = 0;
00278 virtqueue[i].last_used_idx = 0;
00279 memset((char*)&virtqueue[i].queue, 0, sizeof(virtqueue[i].queue));
00280 if (vp_find_vq(nic->ioaddr, i, &virtqueue[i]) == -1)
00281 printf("Cannot register queue #%d\n", i);
00282 }
00283
00284
00285
00286 provide_buffers(nic);
00287
00288
00289
00290 nic->nic_op = &virtnet_operations;
00291
00292
00293
00294 vp_set_features(nic->ioaddr, features & (1 << VIRTIO_NET_F_MAC));
00295 vp_set_status(nic->ioaddr, VIRTIO_CONFIG_S_DRIVER | VIRTIO_CONFIG_S_DRIVER_OK);
00296
00297 return 1;
00298 }
00299
00300 static struct pci_device_id virtnet_nics[] = {
00301 PCI_ROM(0x1af4, 0x1000, "virtio-net", "Virtio Network Interface", 0),
00302 };
00303
00304 PCI_DRIVER ( virtnet_driver, virtnet_nics, PCI_NO_CLASS );
00305
00306 DRIVER ( "VIRTIO-NET", nic_driver, pci_driver, virtnet_driver,
00307 virtnet_probe, virtnet_disable );