Start initializing the virtio-net device
[helenos.git] / uspace / drv / nic / virtio-net / virtio-net.c
blob7dc9b676624cd8947a6e391a3ac1aaa1f34ae32e
1 /*
2 * Copyright (c) 2018 Jakub Jermar
3 * All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
9 * - Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * - Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
14 * - The name of the author may not be used to endorse or promote products
15 * derived from this software without specific prior written permission.
17 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
19 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
20 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
22 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
23 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
24 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
25 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
26 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 #include "virtio-net.h"
31 #include <stdio.h>
32 #include <stdint.h>
34 #include <ddf/driver.h>
35 #include <ddf/log.h>
36 #include <ops/nic.h>
37 #include <pci_dev_iface.h>
39 #include <nic.h>
41 #include <virtio-pci.h>
43 #define NAME "virtio-net"
45 static errno_t virtio_net_initialize(ddf_dev_t *dev)
47 nic_t *nic_data = nic_create_and_bind(dev);
48 if (!nic_data)
49 return ENOMEM;
51 virtio_net_t *virtio_net = calloc(1, sizeof(virtio_net_t));
52 if (!virtio_net) {
53 nic_unbind_and_destroy(dev);
54 return ENOMEM;
57 nic_set_specific(nic_data, virtio_net);
59 errno_t rc = virtio_pci_dev_initialize(dev, &virtio_net->virtio_dev);
60 if (rc != EOK)
61 return rc;
63 virtio_pci_common_cfg_t *cfg = virtio_net->virtio_dev.common_cfg;
64 virtio_net_cfg_t *netcfg = virtio_net->virtio_dev.device_cfg;
67 * Perform device initialization as described in section 3.1.1 of the
68 * specification.
71 /* 1. Reset the device */
72 pio_write_8(&cfg->device_status, VIRTIO_DEV_STATUS_RESET);
74 /* 2. Acknowledge we found the device */
75 pio_write_8(&cfg->device_status, VIRTIO_DEV_STATUS_ACKNOWLEDGE);
77 /* 3. We know how to drive the device */
78 pio_write_8(&cfg->device_status, VIRTIO_DEV_STATUS_DRIVER);
80 /* 4. Read the offered feature flags */
81 pio_write_32(&cfg->device_feature_select, VIRTIO_NET_F_SELECT_PAGE_0);
82 uint32_t features = pio_read_32(&cfg->device_feature);
84 ddf_msg(LVL_NOTE, "offered features %x", features);
85 features &= (1U << VIRTIO_NET_F_MAC);
87 if (!features) {
88 pio_write_8(&cfg->device_status, VIRTIO_DEV_STATUS_FAILED);
89 return ENOTSUP;
92 /* 4. Write the accepted feature flags */
93 pio_write_32(&cfg->driver_feature_select, VIRTIO_NET_F_SELECT_PAGE_0);
94 pio_write_32(&cfg->driver_feature, features);
96 /* 5. Set FEATURES_OK */
97 pio_write_8(&cfg->device_status, VIRTIO_DEV_STATUS_FEATURES_OK);
99 /* 6. Test if the device supports our feature subset */
100 uint8_t status = pio_read_8(&cfg->device_status);
101 if (!(status & VIRTIO_DEV_STATUS_FEATURES_OK)) {
102 pio_write_8(&cfg->device_status, VIRTIO_DEV_STATUS_FAILED);
103 return ENOTSUP;
106 /* 7. Perform device-specific setup */
107 nic_address_t nic_addr;
108 for (unsigned i = 0; i < 6; i++)
109 nic_addr.address[i] = netcfg->mac[i];
110 rc = nic_report_address(nic_data, &nic_addr);
111 if (rc != EOK) {
112 pio_write_8(&cfg->device_status, VIRTIO_DEV_STATUS_FAILED);
113 return rc;
116 ddf_msg(LVL_NOTE, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x",
117 nic_addr.address[0], nic_addr.address[1],
118 nic_addr.address[2], nic_addr.address[3],
119 nic_addr.address[4], nic_addr.address[5]);
121 /* 8. Go live */
122 pio_write_8(&cfg->device_status, VIRTIO_DEV_STATUS_DRIVER_OK);
124 return EOK;
127 static errno_t virtio_net_dev_add(ddf_dev_t *dev)
129 ddf_msg(LVL_NOTE, "%s %s (handle = %zu)", __func__,
130 ddf_dev_get_name(dev), ddf_dev_get_handle(dev));
132 errno_t rc = virtio_net_initialize(dev);
133 if (rc != EOK)
134 return rc;
136 return ENOTSUP;
139 static ddf_dev_ops_t virtio_net_dev_ops;
141 static driver_ops_t virtio_net_driver_ops = {
142 .dev_add = virtio_net_dev_add
145 static driver_t virtio_net_driver = {
146 .name = NAME,
147 .driver_ops = &virtio_net_driver_ops
150 static nic_iface_t virtio_net_nic_iface;
152 int main(void)
154 printf("%s: HelenOS virtio-net driver\n", NAME);
156 if (nic_driver_init(NAME) != EOK)
157 return 1;
159 nic_driver_implement(&virtio_net_driver_ops, &virtio_net_dev_ops,
160 &virtio_net_nic_iface);
162 (void) ddf_log_init(NAME);
163 return ddf_driver_main(&virtio_net_driver);