source: mainline/uspace/drv/nic/rtl8169/driver.c@ 3bacee1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 3bacee1 was 3bacee1, checked in by Jiri Svoboda <jiri@…>, 7 years ago

Make ccheck-fix again and commit more good files.

  • Property mode set to 100644
File size: 32.9 KB
RevLine 
[fef725d]1/*
2 * Copyright (c) 2014 Agnieszka Tabaka
3 * All rights reserved.
4 *
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
7 * are met:
8 *
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.
16 *
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.
27 */
28
29#include <assert.h>
[f300523]30#include <async.h>
[fef725d]31#include <errno.h>
[dd8ab1c]32#include <str_error.h>
[fef725d]33#include <align.h>
34#include <byteorder.h>
35#include <libarch/barrier.h>
[84239b1]36#include <stdbool.h>
[fef725d]37
38#include <as.h>
39#include <ddf/log.h>
40#include <ddf/interrupt.h>
[d51838f]41#include <device/hw_res.h>
42#include <device/hw_res_parsed.h>
[fef725d]43#include <io/log.h>
44#include <nic.h>
45#include <pci_dev_iface.h>
46
47#include <str.h>
48
49#include "defs.h"
50#include "driver.h"
51
52/** Global mutex for work with shared irq structure */
53FIBRIL_MUTEX_INITIALIZE(irq_reg_lock);
54
[b7fd2a0]55static errno_t rtl8169_set_addr(ddf_fun_t *fun, const nic_address_t *addr);
56static errno_t rtl8169_get_device_info(ddf_fun_t *fun, nic_device_info_t *info);
57static errno_t rtl8169_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state);
58static errno_t rtl8169_get_operation_mode(ddf_fun_t *fun, int *speed,
[90782c36]59 nic_channel_mode_t *duplex, nic_role_t *role);
[b7fd2a0]60static errno_t rtl8169_set_operation_mode(ddf_fun_t *fun, int speed,
[90782c36]61 nic_channel_mode_t duplex, nic_role_t role);
[1b20da0]62static errno_t rtl8169_pause_get(ddf_fun_t *fun, nic_result_t *we_send,
[90782c36]63 nic_result_t *we_receive, uint16_t *time);
[1b20da0]64static errno_t rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive,
[90782c36]65 uint16_t time);
[b7fd2a0]66static errno_t rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement);
67static errno_t rtl8169_autoneg_disable(ddf_fun_t *fun);
68static errno_t rtl8169_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
[90782c36]69 uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result);
[b7fd2a0]70static errno_t rtl8169_autoneg_restart(ddf_fun_t *fun);
71static errno_t rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode);
72static errno_t rtl8169_defective_set_mode(ddf_fun_t *fun, uint32_t mode);
73static errno_t rtl8169_on_activated(nic_t *nic_data);
74static errno_t rtl8169_on_stopped(nic_t *nic_data);
[90782c36]75static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size);
[01c3bb4]76static void rtl8169_irq_handler(ipc_call_t *icall, ddf_dev_t *dev);
[eadaeae8]77static inline errno_t rtl8169_register_int_handler(nic_t *nic_data,
78 cap_irq_handle_t *handle);
[90782c36]79static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr);
[96e368a]80static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, const nic_address_t *addr);
[90782c36]81
82static void rtl8169_reset(rtl8169_t *rtl8169);
[b7fd2a0]83static errno_t rtl8169_get_resource_info(ddf_dev_t *dev);
84static errno_t rtl8169_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t *hw_resources);
[90782c36]85static rtl8169_t *rtl8169_create_dev_data(ddf_dev_t *dev);
86
[b7fd2a0]87static errno_t rtl8169_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
[0764cc8a]88 const nic_address_t *, size_t);
[b7fd2a0]89static errno_t rtl8169_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
[0764cc8a]90 const nic_address_t *addr, size_t addr_count);
[b7fd2a0]91static errno_t rtl8169_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode);
[0764cc8a]92
[727e639]93static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr);
94static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value);
[be971233]95static void rtl8169_rx_ring_refill(rtl8169_t *rtl8169, unsigned int first,
96 unsigned int last);
[0764cc8a]97
[fef725d]98/** Network interface options for RTL8169 card driver */
99static nic_iface_t rtl8169_nic_iface = {
100 .set_address = &rtl8169_set_addr,
101 .get_device_info = &rtl8169_get_device_info,
102 .get_cable_state = &rtl8169_get_cable_state,
103 .get_operation_mode = &rtl8169_get_operation_mode,
104 .set_operation_mode = &rtl8169_set_operation_mode,
105
106 .get_pause = &rtl8169_pause_get,
107 .set_pause = &rtl8169_pause_set,
108
109 .autoneg_enable = &rtl8169_autoneg_enable,
110 .autoneg_disable = &rtl8169_autoneg_disable,
111 .autoneg_probe = &rtl8169_autoneg_probe,
112 .autoneg_restart = &rtl8169_autoneg_restart,
113
114 .defective_get_mode = &rtl8169_defective_get_mode,
115 .defective_set_mode = &rtl8169_defective_set_mode,
116};
117
[90782c36]118irq_pio_range_t rtl8169_irq_pio_ranges[] = {
119 {
120 .base = 0,
121 .size = RTL8169_IO_SIZE
122 }
123};
124
125irq_cmd_t rtl8169_irq_commands[] = {
126 {
127 /* Get the interrupt status */
128 .cmd = CMD_PIO_READ_16,
129 .addr = NULL,
130 .dstarg = 2
131 },
132 {
133 .cmd = CMD_PREDICATE,
134 .value = 3,
135 .srcarg = 2
136 },
137 {
138 /* Mark interrupts as solved */
139 .cmd = CMD_PIO_WRITE_16,
140 .addr = NULL,
141 .value = 0xFFFF
142 },
143 {
144 /* Disable interrupts until interrupt routine is finished */
145 .cmd = CMD_PIO_WRITE_16,
146 .addr = NULL,
147 .value = 0x0000
148 },
149 {
150 .cmd = CMD_ACCEPT
151 }
152};
153
154/** Interrupt code definition */
155irq_code_t rtl8169_irq_code = {
156 .rangecount = sizeof(rtl8169_irq_pio_ranges) / sizeof(irq_pio_range_t),
157 .ranges = rtl8169_irq_pio_ranges,
158 .cmdcount = sizeof(rtl8169_irq_commands) / sizeof(irq_cmd_t),
159 .cmds = rtl8169_irq_commands
160};
161
[fef725d]162/** Basic device operations for RTL8169 driver */
163static ddf_dev_ops_t rtl8169_dev_ops;
164
[b7fd2a0]165static errno_t rtl8169_dev_add(ddf_dev_t *dev);
[fef725d]166
167/** Basic driver operations for RTL8169 driver */
168static driver_ops_t rtl8169_driver_ops = {
169 .dev_add = &rtl8169_dev_add,
170};
171
172/** Driver structure for RTL8169 driver */
173static driver_t rtl8169_driver = {
174 .name = NAME,
175 .driver_ops = &rtl8169_driver_ops
176};
177
[b7fd2a0]178static errno_t rtl8169_get_resource_info(ddf_dev_t *dev)
[90782c36]179{
180 assert(dev);
181
182 nic_t *nic_data = nic_get_from_ddf_dev(dev);
183 assert(nic_data);
184
185 hw_res_list_parsed_t hw_res_parsed;
186 hw_res_list_parsed_init(&hw_res_parsed);
187
188 /* Get hw resources form parent driver */
[b7fd2a0]189 errno_t rc = nic_get_resources(nic_data, &hw_res_parsed);
[90782c36]190 if (rc != EOK)
191 return rc;
192
193 /* Fill resources information to the device */
[b7fd2a0]194 errno_t ret = rtl8169_fill_resource_info(dev, &hw_res_parsed);
[90782c36]195 hw_res_list_parsed_clean(&hw_res_parsed);
196
197 return ret;
198}
199
[b7fd2a0]200static errno_t rtl8169_fill_resource_info(ddf_dev_t *dev, const hw_res_list_parsed_t
[90782c36]201 *hw_resources)
202{
203 assert(dev);
204 assert(hw_resources);
205
206 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_dev(dev));
207 assert(rtl8169);
208
209 if (hw_resources->irqs.count != 1) {
210 ddf_msg(LVL_ERROR, "%s device: unexpected irq count", ddf_dev_get_name(dev));
211 return EINVAL;
[850fd32]212 }
[59b3095]213
[90782c36]214 if (hw_resources->io_ranges.count != 1) {
215 ddf_msg(LVL_ERROR, "%s device: unexpected io ranges count", ddf_dev_get_name(dev));
216 return EINVAL;
217 }
218
219 rtl8169->irq = hw_resources->irqs.irqs[0];
220 ddf_msg(LVL_DEBUG, "%s device: irq 0x%x assigned", ddf_dev_get_name(dev), rtl8169->irq);
221
222 rtl8169->regs_phys = (void *)((size_t)RNGABS(hw_resources->io_ranges.ranges[0]));
223 if (hw_resources->io_ranges.ranges[0].size < RTL8169_IO_SIZE) {
224 ddf_msg(LVL_ERROR, "I/O range assigned to the device "
225 "%s is too small.", ddf_dev_get_name(dev));
226 return EINVAL;
227 }
228 ddf_msg(LVL_DEBUG, "%s device: i/o addr %p assigned.", ddf_dev_get_name(dev), rtl8169->regs_phys);
229
230 return EOK;
231}
232
[b7fd2a0]233static errno_t rtl8169_allocate_buffers(rtl8169_t *rtl8169)
[0764cc8a]234{
[b7fd2a0]235 errno_t rc;
[0764cc8a]236
237 ddf_msg(LVL_DEBUG, "Allocating DMA buffer rings");
238
239 /* Allocate TX ring */
[91e057c]240 rtl8169->tx_ring = AS_AREA_ANY;
[1b20da0]241 rc = dmamem_map_anonymous(TX_RING_SIZE, DMAMEM_4GiB,
[0764cc8a]242 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->tx_ring_phys,
[59b3095]243 (void **)&rtl8169->tx_ring);
[0764cc8a]244
245 if (rc != EOK)
246 return rc;
247
[ca652eb]248 ddf_msg(LVL_DEBUG, "TX ring address: phys=0x%#" PRIxn ", virt=%p",
[91e057c]249 rtl8169->tx_ring_phys, rtl8169->tx_ring);
250
[be971233]251 memset(rtl8169->tx_ring, 0, TX_RING_SIZE);
252
[0764cc8a]253 /* Allocate RX ring */
[91e057c]254 rtl8169->rx_ring = AS_AREA_ANY;
[1b20da0]255 rc = dmamem_map_anonymous(RX_RING_SIZE, DMAMEM_4GiB,
[0764cc8a]256 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->rx_ring_phys,
[59b3095]257 (void **)&rtl8169->rx_ring);
[0764cc8a]258
259 if (rc != EOK)
260 return rc;
261
[ca652eb]262 ddf_msg(LVL_DEBUG, "RX ring address: phys=0x%#" PRIxn ", virt=%p",
[91e057c]263 rtl8169->rx_ring_phys, rtl8169->rx_ring);
264
[be971233]265 memset(rtl8169->rx_ring, 0, RX_RING_SIZE);
266
[0764cc8a]267 /* Allocate TX buffers */
[91e057c]268 rtl8169->tx_buff = AS_AREA_ANY;
[1b20da0]269 rc = dmamem_map_anonymous(TX_BUFFERS_SIZE, DMAMEM_4GiB,
[0764cc8a]270 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->tx_buff_phys,
[59b3095]271 &rtl8169->tx_buff);
[0764cc8a]272
273 if (rc != EOK)
274 return rc;
275
[ca652eb]276 ddf_msg(LVL_DEBUG, "TX buffers base address: phys=0x%#" PRIxn " virt=%p",
[91e057c]277 rtl8169->tx_buff_phys, rtl8169->tx_buff);
278
[0764cc8a]279 /* Allocate RX buffers */
[91e057c]280 rtl8169->rx_buff = AS_AREA_ANY;
[1b20da0]281 rc = dmamem_map_anonymous(RX_BUFFERS_SIZE, DMAMEM_4GiB,
[0764cc8a]282 AS_AREA_READ | AS_AREA_WRITE, 0, &rtl8169->rx_buff_phys,
[59b3095]283 &rtl8169->rx_buff);
[0764cc8a]284
285 if (rc != EOK)
286 return rc;
[59b3095]287
[ca652eb]288 ddf_msg(LVL_DEBUG, "RX buffers base address: phys=0x%#" PRIxn ", virt=%p",
[91e057c]289 rtl8169->rx_buff_phys, rtl8169->rx_buff);
290
[59b3095]291 return EOK;
[0764cc8a]292}
293
[90782c36]294static rtl8169_t *rtl8169_create_dev_data(ddf_dev_t *dev)
295{
296 assert(dev);
297 assert(!nic_get_from_ddf_dev(dev));
298
299 nic_t *nic_data = nic_create_and_bind(dev);
300 if (!nic_data)
301 return NULL;
302
303 rtl8169_t *rtl8169 = malloc(sizeof(rtl8169_t));
304 if (!rtl8169) {
305 nic_unbind_and_destroy(dev);
306 return NULL;
307 }
308
309 memset(rtl8169, 0, sizeof(rtl8169_t));
310
311 rtl8169->nic_data = nic_data;
312 nic_set_specific(nic_data, rtl8169);
313 nic_set_send_frame_handler(nic_data, rtl8169_send_frame);
314 nic_set_state_change_handlers(nic_data,
[3bacee1]315 rtl8169_on_activated, NULL, rtl8169_on_stopped);
[90782c36]316 nic_set_filtering_change_handlers(nic_data,
[3bacee1]317 rtl8169_unicast_set, rtl8169_multicast_set, rtl8169_broadcast_set,
318 NULL, NULL);
[90782c36]319
320 fibril_mutex_initialize(&rtl8169->rx_lock);
321 fibril_mutex_initialize(&rtl8169->tx_lock);
322
323 nic_set_wol_max_caps(nic_data, NIC_WV_BROADCAST, 1);
324 nic_set_wol_max_caps(nic_data, NIC_WV_LINK_CHANGE, 1);
325 nic_set_wol_max_caps(nic_data, NIC_WV_MAGIC_PACKET, 1);
326
327 return rtl8169;
328}
329
[2ff9876]330static void rtl8169_dev_cleanup(ddf_dev_t *dev)
331{
332 assert(dev);
333
334 if (ddf_dev_data_get(dev))
335 nic_unbind_and_destroy(dev);
336}
337
[b7fd2a0]338static errno_t rtl8169_dev_initialize(ddf_dev_t *dev)
[90782c36]339{
[b7fd2a0]340 errno_t ret;
[90782c36]341
342 rtl8169_t *rtl8169 = rtl8169_create_dev_data(dev);
343 if (rtl8169 == NULL) {
344 ddf_msg(LVL_ERROR, "Not enough memory for initializing %s.", ddf_dev_get_name(dev));
345 return ENOMEM;
346 }
347
348 ret = rtl8169_get_resource_info(dev);
349 if (ret != EOK) {
350 ddf_msg(LVL_ERROR, "Can't obtain H/W resources information");
351 goto failed;
352 }
353
354 ddf_msg(LVL_DEBUG, "The device is initialized");
355 return ret;
[a35b458]356
[90782c36]357failed:
358 ddf_msg(LVL_ERROR, "The device initialization failed");
[2ff9876]359 rtl8169_dev_cleanup(dev);
[90782c36]360 return ret;
361
362}
363
[eadaeae8]364inline static errno_t rtl8169_register_int_handler(nic_t *nic_data,
365 cap_irq_handle_t *handle)
[90782c36]366{
367 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
368
369 rtl8169_irq_code.ranges[0].base = (uintptr_t) rtl8169->regs;
370 rtl8169_irq_code.cmds[0].addr = rtl8169->regs + ISR;
371 rtl8169_irq_code.cmds[2].addr = rtl8169->regs + ISR;
372 rtl8169_irq_code.cmds[3].addr = rtl8169->regs + IMR;
[b7fd2a0]373 errno_t rc = register_interrupt_handler(nic_get_ddf_dev(nic_data),
[071a1ddb]374 rtl8169->irq, rtl8169_irq_handler, &rtl8169_irq_code, handle);
[90782c36]375
[071a1ddb]376 return rc;
[90782c36]377}
378
[b7fd2a0]379static errno_t rtl8169_dev_add(ddf_dev_t *dev)
[fef725d]380{
381 ddf_fun_t *fun;
[90782c36]382 nic_address_t nic_addr;
[b7fd2a0]383 errno_t rc;
[fef725d]384
385 assert(dev);
386 ddf_msg(LVL_NOTE, "RTL8169_dev_add %s (handle = %zu)",
387 ddf_dev_get_name(dev), ddf_dev_get_handle(dev));
388
[90782c36]389
[fef725d]390 /* Init structures */
391 rc = rtl8169_dev_initialize(dev);
392 if (rc != EOK)
393 return rc;
394
[90782c36]395 nic_t *nic_data = nic_get_from_ddf_dev(dev);
396 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
397
[d51838f]398 rtl8169->dev = dev;
399 rtl8169->parent_sess = ddf_dev_parent_sess_get(dev);
400 if (rtl8169->parent_sess == NULL)
401 return EIO;
402
[cbfece7]403 /* Get PCI VID & PID */
[d51838f]404 rc = pci_config_space_read_16(rtl8169->parent_sess, PCI_VENDOR_ID,
405 &rtl8169->pci_vid);
[cbfece7]406 if (rc != EOK)
407 return rc;
408
[d51838f]409 rc = pci_config_space_read_16(rtl8169->parent_sess, PCI_DEVICE_ID,
410 &rtl8169->pci_pid);
[cbfece7]411 if (rc != EOK)
412 return rc;
413
[90782c36]414 /* Map register space */
415 rc = pio_enable(rtl8169->regs_phys, RTL8169_IO_SIZE, &rtl8169->regs);
416 if (rc != EOK) {
417 ddf_msg(LVL_ERROR, "Cannot map register space for device %s.",
418 ddf_dev_get_name(dev));
419 goto err_destroy;
420 }
421
422 /* Read MAC address and print it */
423 rtl8169_get_hwaddr(rtl8169, &nic_addr);
424 ddf_msg(LVL_NOTE, "MAC address: %02x:%02x:%02x:%02x:%02x:%02x",
425 nic_addr.address[0], nic_addr.address[1],
426 nic_addr.address[2], nic_addr.address[3],
427 nic_addr.address[4], nic_addr.address[5]);
428
429 rc = nic_report_address(nic_data, &nic_addr);
430 if (rc != EOK)
431 goto err_pio;
432
[eadaeae8]433 cap_irq_handle_t irq_handle;
434 rc = rtl8169_register_int_handler(nic_data, &irq_handle);
[071a1ddb]435 if (rc != EOK) {
[dd8ab1c]436 ddf_msg(LVL_ERROR, "Failed to register IRQ handler (%s)", str_error_name(rc));
[90782c36]437 goto err_irq;
438 }
439
440 ddf_msg(LVL_DEBUG, "Interrupt handler installed");
441
442 uint8_t cr_value = pio_read_8(rtl8169->regs + CR);
443 pio_write_8(rtl8169->regs + CR, cr_value | CR_TE | CR_RE);
444
445 fun = ddf_fun_create(nic_get_ddf_dev(nic_data), fun_exposed, "port0");
446 if (fun == NULL) {
447 ddf_msg(LVL_ERROR, "Failed creating device function");
448 goto err_srv;
449 }
450
451 nic_set_ddf_fun(nic_data, fun);
452 ddf_fun_set_ops(fun, &rtl8169_dev_ops);
453
454 rc = ddf_fun_bind(fun);
455 if (rc != EOK) {
456 ddf_msg(LVL_ERROR, "Failed binding device function");
457 goto err_fun_create;
458 }
459
460 rc = ddf_fun_add_to_category(fun, DEVICE_CATEGORY_NIC);
461 if (rc != EOK) {
462 ddf_msg(LVL_ERROR, "Failed adding function to category");
463 goto err_fun_bind;
464 }
[a35b458]465
[90782c36]466 ddf_msg(LVL_NOTE, "The %s device has been successfully initialized.",
467 ddf_dev_get_name(dev));
468 return EOK;
469
470err_fun_bind:
471 ddf_fun_unbind(fun);
472err_fun_create:
473 ddf_fun_destroy(fun);
474err_srv:
475 /* XXX Disconnect from services */
[eadaeae8]476 unregister_interrupt_handler(dev, irq_handle);
[90782c36]477err_irq:
478err_pio:
479err_destroy:
[2ff9876]480 rtl8169_dev_cleanup(dev);
[90782c36]481 return rc;
482
[fef725d]483 return EOK;
484}
485
[b7fd2a0]486static errno_t rtl8169_set_addr(ddf_fun_t *fun, const nic_address_t *addr)
[fef725d]487{
[96e368a]488 nic_t *nic_data = nic_get_from_ddf_fun(fun);
489 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
[b7fd2a0]490 errno_t rc;
[96e368a]491
[cbfece7]492 fibril_mutex_lock(&rtl8169->rx_lock);
493 fibril_mutex_lock(&rtl8169->tx_lock);
[96e368a]494
495 rc = nic_report_address(nic_data, addr);
496 if (rc != EOK)
497 return rc;
498
[cbfece7]499 rtl8169_set_hwaddr(rtl8169, addr);
500
501 fibril_mutex_unlock(&rtl8169->rx_lock);
502 fibril_mutex_unlock(&rtl8169->tx_lock);
503
[fef725d]504 return EOK;
505}
506
[b7fd2a0]507static errno_t rtl8169_get_device_info(ddf_fun_t *fun, nic_device_info_t *info)
[fef725d]508{
[cbfece7]509 nic_t *nic_data = nic_get_from_ddf_fun(fun);
510 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
[5a78e4e]511
[cbfece7]512 str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "Unknown");
513 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "Unknown");
514
515 if (rtl8169->pci_vid == PCI_VID_REALTEK)
516 str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "Realtek");
[a35b458]517
[cbfece7]518 if (rtl8169->pci_vid == PCI_VID_DLINK)
519 str_cpy(info->vendor_name, NIC_VENDOR_MAX_LENGTH, "D-Link");
[a35b458]520
[cbfece7]521 if (rtl8169->pci_pid == 0x8168)
522 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8168");
[a35b458]523
[cbfece7]524 if (rtl8169->pci_pid == 0x8169)
525 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8169");
526
527 if (rtl8169->pci_pid == 0x8110)
528 str_cpy(info->model_name, NIC_MODEL_MAX_LENGTH, "RTL8110");
[5a78e4e]529
[fef725d]530 return EOK;
531}
532
[b7fd2a0]533static errno_t rtl8169_get_cable_state(ddf_fun_t *fun, nic_cable_state_t *state)
[fef725d]534{
[5a78e4e]535 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
536 uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
537
538 if (phystatus & PHYSTATUS_LINK)
539 *state = NIC_CS_PLUGGED;
540 else
541 *state = NIC_CS_UNPLUGGED;
542
[fef725d]543 return EOK;
544}
545
[b7fd2a0]546static errno_t rtl8169_get_operation_mode(ddf_fun_t *fun, int *speed,
[fef725d]547 nic_channel_mode_t *duplex, nic_role_t *role)
548{
[727e639]549 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
550 uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
551
[3bacee1]552 *duplex = phystatus & PHYSTATUS_FDX ?
553 NIC_CM_FULL_DUPLEX : NIC_CM_HALF_DUPLEX;
[727e639]554
555 if (phystatus & PHYSTATUS_10M)
556 *speed = 10;
557
558 if (phystatus & PHYSTATUS_100M)
559 *speed = 100;
560
561 if (phystatus & PHYSTATUS_1000M)
562 *speed = 1000;
563
564 *role = NIC_ROLE_UNKNOWN;
[fef725d]565 return EOK;
566}
567
[b7fd2a0]568static errno_t rtl8169_set_operation_mode(ddf_fun_t *fun, int speed,
[fef725d]569 nic_channel_mode_t duplex, nic_role_t role)
570{
[727e639]571 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
572 uint16_t bmcr;
573
574 if (speed != 10 && speed != 100 && speed != 1000)
575 return EINVAL;
576
[3bacee1]577 if (duplex != NIC_CM_HALF_DUPLEX && duplex != NIC_CM_FULL_DUPLEX)
[727e639]578 return EINVAL;
579
580 bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
581 bmcr &= ~(BMCR_DUPLEX | BMCR_SPD_100 | BMCR_SPD_1000);
[a35b458]582
[cbfece7]583 /* Disable autonegotiation */
584 bmcr &= ~BMCR_AN_ENABLE;
585
[727e639]586 if (duplex == NIC_CM_FULL_DUPLEX)
587 bmcr |= BMCR_DUPLEX;
588
589 if (speed == 100)
590 bmcr |= BMCR_SPD_100;
591
592 if (speed == 1000)
593 bmcr |= BMCR_SPD_1000;
594
595 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
[fef725d]596 return EOK;
597}
598
[1b20da0]599static errno_t rtl8169_pause_get(ddf_fun_t *fun, nic_result_t *we_send,
[fef725d]600 nic_result_t *we_receive, uint16_t *time)
601{
602 return EOK;
[90782c36]603}
[fef725d]604
[1b20da0]605static errno_t rtl8169_pause_set(ddf_fun_t *fun, int allow_send, int allow_receive,
[fef725d]606 uint16_t time)
607{
608 return EOK;
609}
610
[b7fd2a0]611static errno_t rtl8169_autoneg_enable(ddf_fun_t *fun, uint32_t advertisement)
[fef725d]612{
[727e639]613 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
614 uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
615 uint16_t anar = ANAR_SELECTOR;
616
617 if (advertisement & ETH_AUTONEG_10BASE_T_FULL)
618 anar |= ANAR_10_FD;
619 if (advertisement & ETH_AUTONEG_10BASE_T_HALF)
620 anar |= ANAR_10_HD;
621 if (advertisement & ETH_AUTONEG_100BASE_TX_FULL)
622 anar |= ANAR_100TX_FD;
623 if (advertisement & ETH_AUTONEG_100BASE_TX_HALF)
624 anar |= ANAR_100TX_HD;
625 if (advertisement & ETH_AUTONEG_PAUSE_SYMETRIC)
626 anar |= ANAR_PAUSE;
627
628 bmcr |= BMCR_AN_ENABLE;
629 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
630 rtl8169_mii_write(rtl8169, MII_ANAR, anar);
631
[fef725d]632 return EOK;
633}
634
[b7fd2a0]635static errno_t rtl8169_autoneg_disable(ddf_fun_t *fun)
[fef725d]636{
[727e639]637 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
638 uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
639
640 bmcr &= ~BMCR_AN_ENABLE;
641 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
642
[fef725d]643 return EOK;
644}
645
[b7fd2a0]646static errno_t rtl8169_autoneg_probe(ddf_fun_t *fun, uint32_t *advertisement,
[fef725d]647 uint32_t *their_adv, nic_result_t *result, nic_result_t *their_result)
648{
649 return EOK;
650}
651
[b7fd2a0]652static errno_t rtl8169_autoneg_restart(ddf_fun_t *fun)
[fef725d]653{
[cbfece7]654 rtl8169_t *rtl8169 = nic_get_specific(nic_get_from_ddf_fun(fun));
655 uint16_t bmcr = rtl8169_mii_read(rtl8169, MII_BMCR);
656
657 bmcr |= BMCR_AN_ENABLE;
658 rtl8169_mii_write(rtl8169, MII_BMCR, bmcr);
[fef725d]659 return EOK;
660}
661
[b7fd2a0]662static errno_t rtl8169_defective_get_mode(ddf_fun_t *fun, uint32_t *mode)
[fef725d]663{
664 return EOK;
665}
666
[b7fd2a0]667static errno_t rtl8169_defective_set_mode(ddf_fun_t *fun, uint32_t mode)
[fef725d]668{
669 return EOK;
670}
671
[be971233]672static void rtl8169_rx_ring_refill(rtl8169_t *rtl8169, unsigned int first,
673 unsigned int last)
674{
675 rtl8169_descr_t *descr;
[ca652eb]676 uint64_t buff_phys;
[be971233]677 unsigned int i = first;
678
[84239b1]679 while (true) {
[be971233]680 descr = &rtl8169->rx_ring[i];
681 buff_phys = rtl8169->rx_buff_phys + (BUFFER_SIZE * i);
682 descr->control = BUFFER_SIZE | CONTROL_OWN;
683 descr->buf_low = buff_phys & 0xffffffff;
684 descr->buf_high = (buff_phys >> 32) & 0xffffffff;
685
686 if (i == RX_BUFFERS_COUNT - 1)
687 descr->control |= CONTROL_EOR;
688
689 if (i == last)
690 break;
691
692 i = (i + 1) % RX_BUFFERS_COUNT;
693 }
694}
695
[b7fd2a0]696static errno_t rtl8169_on_activated(nic_t *nic_data)
[90782c36]697{
[b7fd2a0]698 errno_t rc;
[ca652eb]699 uint64_t tmp;
[91e057c]700
[90782c36]701 ddf_msg(LVL_NOTE, "Activating device");
702
703 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
704
[0764cc8a]705 /* Reset card */
706 pio_write_8(rtl8169->regs + CONFIG0, 0);
707 rtl8169_reset(rtl8169);
708
[59b3095]709 /* Allocate buffers */
[91e057c]710 rc = rtl8169_allocate_buffers(rtl8169);
711 if (rc != EOK) {
[dd8ab1c]712 ddf_msg(LVL_ERROR, "Error allocating buffers: %s", str_error_name(rc));
[91e057c]713 return 0;
714 }
[59b3095]715
[be971233]716 /* Initialize RX ring */
717 rtl8169_rx_ring_refill(rtl8169, 0, RX_BUFFERS_COUNT - 1);
718
[59b3095]719 /* Write address of descriptor as start of TX ring */
[ca652eb]720 tmp = rtl8169->tx_ring_phys;
721 pio_write_32(rtl8169->regs + TNPDS, tmp & 0xffffffff);
722 pio_write_32(rtl8169->regs + TNPDS + 4, (tmp >> 32) & 0xffffffff);
[59b3095]723 rtl8169->tx_head = 0;
724 rtl8169->tx_tail = 0;
725 rtl8169->tx_ring[15].control = CONTROL_EOR;
726
[be971233]727 /* Write RX ring address */
[ca652eb]728 tmp = rtl8169->rx_ring_phys;
729 pio_write_32(rtl8169->regs + RDSAR, tmp & 0xffffffff);
730 pio_write_32(rtl8169->regs + RDSAR + 4, (tmp >> 32) & 0xffffffff);
[be971233]731 rtl8169->rx_head = 0;
732 rtl8169->rx_tail = 0;
733
734 /* Clear pending interrupts */
735 pio_write_16(rtl8169->regs + ISR, 0xffff);
736
[0764cc8a]737 /* Enable TX and RX */
738 uint8_t cr = pio_read_8(rtl8169->regs + CR);
739 cr |= CR_TE | CR_RE;
740 pio_write_8(rtl8169->regs + CR, cr);
[be971233]741 pio_write_32(rtl8169->regs + MAR0, 0xffffffff);
742 pio_write_32(rtl8169->regs + MAR0 + 4, 0xffffffff);
743
744 /* Configure Receive Control Register */
745 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
[320bd52]746 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH;
[2ff9876]747 rcr |= RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ERROR | RCR_ACCEPT_RUNT;
[be971233]748 pio_write_32(rtl8169->regs + RCR, rcr);
749 pio_write_16(rtl8169->regs + RMS, BUFFER_SIZE);
750
[90782c36]751 pio_write_16(rtl8169->regs + IMR, 0xffff);
[d51838f]752 /* XXX Check return value */
753 hw_res_enable_interrupt(rtl8169->parent_sess, rtl8169->irq);
[90782c36]754
755 return EOK;
756}
757
[b7fd2a0]758static errno_t rtl8169_on_stopped(nic_t *nic_data)
[90782c36]759{
[0764cc8a]760 ddf_msg(LVL_NOTE, "Stopping device");
[90782c36]761 return EOK;
762}
763
764inline static void rtl8169_reset(rtl8169_t *rtl8169)
765{
766 pio_write_8(rtl8169->regs + CR, CR_RST);
767 memory_barrier();
768 while (pio_read_8(rtl8169->regs + CR) & CR_RST) {
[f300523]769 async_usleep(1);
[90782c36]770 read_barrier();
771 }
772}
773
774static void rtl8169_link_change(ddf_dev_t *dev)
775{
776 nic_t *nic_data = nic_get_from_ddf_dev(dev);
777 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
778
779 uint8_t phystatus = pio_read_8(rtl8169->regs + PHYSTATUS);
780
781 if (phystatus & PHYSTATUS_LINK) {
782 ddf_msg(LVL_NOTE, "%s: Link up", ddf_dev_get_name(dev));
783
784 int speed;
785 const char *fdx = phystatus & PHYSTATUS_FDX ? "full duplex" : "half duplex";
786
787 if (phystatus & PHYSTATUS_10M)
788 speed = 10;
789
790 if (phystatus & PHYSTATUS_100M)
791 speed = 100;
792
793 if (phystatus & PHYSTATUS_1000M)
794 speed = 1000;
795
796 ddf_msg(LVL_NOTE, "%s: Speed %dMbit/s, %s", ddf_dev_get_name(dev), speed, fdx);
797 } else {
798 ddf_msg(LVL_NOTE, "%s: Link down", ddf_dev_get_name(dev));
799 }
800
801}
802
[320bd52]803/** Notify NIC framework about HW filtering state when promisc mode was disabled
804 *
805 * @param nic_data The NIC data
806 * @param mcast_mode Current multicast mode
807 * @param was_promisc Sign if the promiscuous mode was active before disabling
808 */
809inline static void rtl8169_rcx_promics_rem(nic_t *nic_data,
810 nic_multicast_mode_t mcast_mode, uint8_t was_promisc)
811{
812 assert(nic_data);
813
814 if (was_promisc != 0) {
815 if (mcast_mode == NIC_MULTICAST_LIST)
816 nic_report_hw_filtering(nic_data, 1, 0, -1);
817 else
818 nic_report_hw_filtering(nic_data, 1, 1, -1);
819 } else {
820 nic_report_hw_filtering(nic_data, 1, -1, -1);
821 }
822}
823
[b7fd2a0]824static errno_t rtl8169_unicast_set(nic_t *nic_data, nic_unicast_mode_t mode,
[0764cc8a]825 const nic_address_t *addr, size_t addr_count)
826{
[320bd52]827 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
828 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
829 uint8_t was_promisc = rcr & RCR_ACCEPT_ALL_PHYS;
830 nic_multicast_mode_t mcast_mode;
831
832 nic_query_multicast(nic_data, &mcast_mode, 0, NULL, NULL);
833
834 ddf_msg(LVL_DEBUG, "Unicast RX filter mode: %d", mode);
835
836
837 switch (mode) {
838 case NIC_UNICAST_BLOCKED:
839 rtl8169->rcr_ucast = 0;
840 rtl8169_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
841 break;
842 case NIC_UNICAST_DEFAULT:
843 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH;
844 rtl8169_rcx_promics_rem(nic_data, mcast_mode, was_promisc);
845 break;
846 case NIC_UNICAST_LIST:
847 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS;
848
849 if (mcast_mode == NIC_MULTICAST_PROMISC)
850 nic_report_hw_filtering(nic_data, 0, 1, -1);
851 else
852 nic_report_hw_filtering(nic_data, 0, 0, -1);
853 break;
854 case NIC_UNICAST_PROMISC:
855 rtl8169->rcr_ucast = RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS;
856
857 if (mcast_mode == NIC_MULTICAST_PROMISC)
858 nic_report_hw_filtering(nic_data, 1, 1, -1);
859 else
860 nic_report_hw_filtering(nic_data, 1, 0, -1);
861 break;
862 default:
863 return ENOTSUP;
864 }
865
866 fibril_mutex_lock(&rtl8169->rx_lock);
867
868 rcr &= ~(RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS);
869 pio_write_32(rtl8169->regs + RCR, rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
870 ddf_msg(LVL_DEBUG, "new RCR value: 0x%08x", rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
871
872 fibril_mutex_unlock(&rtl8169->rx_lock);
[0764cc8a]873 return EOK;
874}
875
[b7fd2a0]876static errno_t rtl8169_multicast_set(nic_t *nic_data, nic_multicast_mode_t mode,
[0764cc8a]877 const nic_address_t *addr, size_t addr_count)
878{
[320bd52]879 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
880 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
881 uint64_t mask;
882
883 ddf_msg(LVL_DEBUG, "Multicast RX filter mode: %d", mode);
884
885 switch (mode) {
886 case NIC_MULTICAST_BLOCKED:
887 rtl8169->rcr_mcast = 0;
888 if ((rtl8169->rcr_ucast & RCR_ACCEPT_ALL_PHYS) != 0)
889 nic_report_hw_filtering(nic_data, -1, 0, -1);
890 else
891 nic_report_hw_filtering(nic_data, -1, 1, -1);
892 break;
893 case NIC_MULTICAST_LIST:
894 mask = nic_mcast_hash(addr, addr_count);
895 pio_write_32(rtl8169->regs + MAR0, (uint32_t)mask);
896 pio_write_32(rtl8169->regs + MAR0 + 4, (uint32_t)(mask >> 32));
897 rtl8169->rcr_mcast = RCR_ACCEPT_MULTICAST;
898 nic_report_hw_filtering(nic_data, -1, 0, -1);
899 break;
900 case NIC_MULTICAST_PROMISC:
901 pio_write_32(rtl8169->regs + MAR0, 0xffffffffULL);
902 pio_write_32(rtl8169->regs + MAR0 + 4, (uint32_t)(0xffffffffULL >> 32));
903 rtl8169->rcr_mcast = RCR_ACCEPT_MULTICAST;
904 nic_report_hw_filtering(nic_data, -1, 1, -1);
905 break;
906 default:
907 return ENOTSUP;
908 }
909
910 fibril_mutex_lock(&rtl8169->rx_lock);
911
912 rcr &= ~(RCR_ACCEPT_PHYS_MATCH | RCR_ACCEPT_ALL_PHYS);
913 pio_write_32(rtl8169->regs + RCR, rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
914 ddf_msg(LVL_DEBUG, "new RCR value: 0x%08x", rcr | rtl8169->rcr_ucast | rtl8169->rcr_mcast);
915
916 fibril_mutex_unlock(&rtl8169->rx_lock);
[0764cc8a]917 return EOK;
918}
919
[b7fd2a0]920static errno_t rtl8169_broadcast_set(nic_t *nic_data, nic_broadcast_mode_t mode)
[0764cc8a]921{
[2ff9876]922 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
[a35b458]923
[2ff9876]924 /* Configure Receive Control Register */
925 uint32_t rcr = pio_read_32(rtl8169->regs + RCR);
[320bd52]926
927 ddf_msg(LVL_DEBUG, "Broadcast RX filter mode: %d", mode);
928
929 switch (mode) {
930 case NIC_BROADCAST_BLOCKED:
[a4666a9]931 rcr &= ~RCR_ACCEPT_BROADCAST;
[320bd52]932 break;
933 case NIC_BROADCAST_ACCEPTED:
934 rcr |= RCR_ACCEPT_BROADCAST;
935 break;
936 default:
937 return ENOTSUP;
938 }
939
[2ff9876]940 pio_write_32(rtl8169->regs + RCR, rcr);
[3bacee1]941 ddf_msg(LVL_DEBUG, " new RCR value: 0x%08x", rcr);
[320bd52]942
[0764cc8a]943 return EOK;
944}
945
[59b3095]946static void rtl8169_transmit_done(ddf_dev_t *dev)
947{
948 unsigned int tail, head;
949 nic_t *nic_data = nic_get_from_ddf_dev(dev);
950 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
951 rtl8169_descr_t *descr;
[2f11e6c9]952 int sent = 0;
[59b3095]953
[2f11e6c9]954 ddf_msg(LVL_DEBUG, "rtl8169_transmit_done()");
[59b3095]955
956 fibril_mutex_lock(&rtl8169->tx_lock);
[0764cc8a]957
[59b3095]958 head = rtl8169->tx_head;
959 tail = rtl8169->tx_tail;
960
961 while (tail != head) {
962 descr = &rtl8169->tx_ring[tail];
[91e057c]963 descr->control &= (~CONTROL_OWN);
964 write_barrier();
[2f11e6c9]965 ddf_msg(LVL_DEBUG, "TX status for descr %d: 0x%08x", tail, descr->control);
[a35b458]966
[be971233]967 tail = (tail + 1) % TX_BUFFERS_COUNT;
[2f11e6c9]968 sent++;
[59b3095]969 }
970
[2f11e6c9]971 if (sent != 0)
972 nic_set_tx_busy(nic_data, 0);
973
[59b3095]974 rtl8169->tx_tail = tail;
975
976 fibril_mutex_unlock(&rtl8169->tx_lock);
977}
[0764cc8a]978
[be971233]979static void rtl8169_receive_done(ddf_dev_t *dev)
980{
981 nic_t *nic_data = nic_get_from_ddf_dev(dev);
982 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
983 rtl8169_descr_t *descr;
984 nic_frame_list_t *frames = nic_alloc_frame_list();
985 nic_frame_t *frame;
986 void *buffer;
987 unsigned int tail, fsidx = 0;
988 int frame_size;
989
[2f11e6c9]990 ddf_msg(LVL_DEBUG, "rtl8169_receive_done()");
[be971233]991
992 fibril_mutex_lock(&rtl8169->rx_lock);
993
994 tail = rtl8169->rx_tail;
995
[84239b1]996 while (true) {
[be971233]997 descr = &rtl8169->rx_ring[tail];
998
999 if (descr->control & CONTROL_OWN)
1000 break;
1001
1002 if (descr->control & RXSTATUS_RES) {
[2f11e6c9]1003 ddf_msg(LVL_WARN, "error at slot %d: 0x%08x\n", tail, descr->control);
[be971233]1004 tail = (tail + 1) % RX_BUFFERS_COUNT;
1005 continue;
1006 }
1007
1008 if (descr->control & CONTROL_FS)
1009 fsidx = tail;
[a35b458]1010
[be971233]1011 if (descr->control & CONTROL_LS) {
[2f11e6c9]1012 ddf_msg(LVL_DEBUG, "received message at slot %d, control 0x%08x", tail, descr->control);
[be971233]1013
1014 if (fsidx != tail)
1015 ddf_msg(LVL_WARN, "single frame spanning multiple descriptors");
1016
1017 frame_size = descr->control & 0x1fff;
1018 buffer = rtl8169->rx_buff + (BUFFER_SIZE * tail);
1019 frame = nic_alloc_frame(nic_data, frame_size);
1020 memcpy(frame->data, buffer, frame_size);
1021 nic_frame_list_append(frames, frame);
1022 }
1023
1024 tail = (tail + 1) % RX_BUFFERS_COUNT;
1025 }
1026
1027 rtl8169_rx_ring_refill(rtl8169, rtl8169->rx_tail, tail);
1028
1029 rtl8169->rx_tail = tail;
1030
1031 fibril_mutex_unlock(&rtl8169->rx_lock);
1032
1033 nic_received_frame_list(nic_data, frames);
1034
1035}
1036
[01c3bb4]1037static void rtl8169_irq_handler(ipc_call_t *icall, ddf_dev_t *dev)
[90782c36]1038{
1039 assert(dev);
1040 assert(icall);
1041
[9d653e3]1042 uint16_t isr = (uint16_t) IPC_GET_ARG2(*icall) & INT_KNOWN;
[90782c36]1043 nic_t *nic_data = nic_get_from_ddf_dev(dev);
1044 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
1045
[2f11e6c9]1046 ddf_msg(LVL_DEBUG, "rtl8169_irq_handler(): isr=0x%04x", isr);
[91e057c]1047 pio_write_16(rtl8169->regs + IMR, 0xffff);
[59b3095]1048
[9d653e3]1049 while (isr != 0) {
[91e057c]1050 ddf_msg(LVL_DEBUG, "irq handler: remaining isr=0x%04x", isr);
1051
[9d653e3]1052 /* Packet underrun or link change */
1053 if (isr & INT_PUN) {
1054 rtl8169_link_change(dev);
1055 pio_write_16(rtl8169->regs + ISR, INT_PUN);
1056 }
[59b3095]1057
[9d653e3]1058 /* Transmit notification */
1059 if (isr & (INT_TER | INT_TOK | INT_TDU)) {
1060 rtl8169_transmit_done(dev);
1061 pio_write_16(rtl8169->regs + ISR, (INT_TER | INT_TOK | INT_TDU));
1062 }
[90782c36]1063
[cbfece7]1064 /* Receive underrun */
1065 if (isr & INT_RXOVW) {
1066 /* just ack.. */
1067 pio_write_16(rtl8169->regs + ISR, INT_RXOVW);
1068 }
1069
[9d653e3]1070 if (isr & INT_SERR) {
1071 ddf_msg(LVL_ERROR, "System error interrupt");
1072 pio_write_16(rtl8169->regs + ISR, INT_SERR);
1073 }
[59b3095]1074
[9d653e3]1075 if (isr & (INT_RER | INT_ROK)) {
1076 rtl8169_receive_done(dev);
1077 pio_write_16(rtl8169->regs + ISR, (INT_RER | INT_ROK));
1078 }
1079
1080 isr = pio_read_16(rtl8169->regs + ISR) & INT_KNOWN;
1081 }
[59b3095]1082
[9d653e3]1083 pio_write_16(rtl8169->regs + ISR, 0xffff);
[90782c36]1084}
1085
[fef725d]1086static void rtl8169_send_frame(nic_t *nic_data, void *data, size_t size)
1087{
[59b3095]1088 rtl8169_descr_t *descr, *prev;
1089 unsigned int head, tail;
1090 void *buff;
[ca652eb]1091 uint64_t buff_phys;
[59b3095]1092 rtl8169_t *rtl8169 = nic_get_specific(nic_data);
1093
1094 if (size > RTL8169_FRAME_MAX_LENGTH) {
1095 ddf_msg(LVL_ERROR, "Send frame: frame too long, %zu bytes",
1096 size);
1097 nic_report_send_error(nic_data, NIC_SEC_OTHER, 1);
1098 }
1099
1100 fibril_mutex_lock(&rtl8169->tx_lock);
1101
[2f11e6c9]1102 ddf_msg(LVL_DEBUG, "send_frame: size: %zu, tx_head=%d tx_tail=%d",
[91e057c]1103 size, rtl8169->tx_head, rtl8169->tx_tail);
[59b3095]1104
1105 head = rtl8169->tx_head;
1106 tail = rtl8169->tx_tail;
1107
[be971233]1108 if ((head + 1) % TX_BUFFERS_COUNT == tail) {
[59b3095]1109 /* Queue is full */
[be971233]1110 ddf_msg(LVL_WARN, "TX queue full!");
[59b3095]1111 nic_set_tx_busy(nic_data, 1);
1112 }
1113
1114 /* Calculate address of next free buffer and descriptor */
1115 buff = rtl8169->tx_buff + (BUFFER_SIZE * head);
1116 buff_phys = rtl8169->tx_buff_phys + (BUFFER_SIZE * head);
1117
1118 /* Copy frame */
1119 memcpy(buff, data, size);
1120
1121 /* Setup descriptor */
1122 descr = &rtl8169->tx_ring[head];
1123 prev = &rtl8169->tx_ring[(head - 1) % TX_BUFFERS_COUNT];
1124
[2f11e6c9]1125 ddf_msg(LVL_DEBUG, "current_descr=%p, prev_descr=%p", descr, prev);
[59b3095]1126
1127 descr->control = CONTROL_OWN | CONTROL_FS | CONTROL_LS;
1128 descr->control |= size & 0xffff;
1129 descr->vlan = 0;
1130 descr->buf_low = buff_phys & 0xffffffff;
1131 descr->buf_high = (buff_phys >> 32) & 0xffffffff;
1132
[be971233]1133 if (head == TX_BUFFERS_COUNT - 1)
1134 descr->control |= CONTROL_EOR;
1135
1136 rtl8169->tx_head = (head + 1) % TX_BUFFERS_COUNT;
[59b3095]1137
[91e057c]1138 ddf_msg(LVL_DEBUG, "control: 0x%08x", descr->control);
1139
[59b3095]1140 write_barrier();
1141
1142 /* Notify NIC of pending packets */
1143 pio_write_8(rtl8169->regs + TPPOLL, TPPOLL_NPQ);
[9d653e3]1144 write_barrier();
1145
[59b3095]1146 fibril_mutex_unlock(&rtl8169->tx_lock);
[fef725d]1147}
1148
[90782c36]1149static inline void rtl8169_get_hwaddr(rtl8169_t *rtl8169, nic_address_t *addr)
1150{
1151 int i;
1152
1153 assert(rtl8169);
1154 assert(addr);
1155
1156 for (i = 0; i < 6; i++)
1157 addr->address[i] = pio_read_8(rtl8169->regs + MAC0 + i);
1158}
1159
[96e368a]1160static inline void rtl8169_set_hwaddr(rtl8169_t *rtl8169, const nic_address_t *addr)
[90782c36]1161{
1162 int i;
1163
1164 assert(rtl8169);
1165 assert(addr);
1166
1167 for (i = 0; i < 6; i++)
[96e368a]1168 pio_write_8(rtl8169->regs + MAC0 + i, addr->address[i]);
[90782c36]1169}
1170
[727e639]1171static uint16_t rtl8169_mii_read(rtl8169_t *rtl8169, uint8_t addr)
1172{
1173 uint32_t phyar;
1174
[3bacee1]1175 phyar = PHYAR_RW_READ |
1176 ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT);
[727e639]1177
1178 pio_write_32(rtl8169->regs + PHYAR, phyar);
1179
1180 do {
1181 phyar = pio_read_32(rtl8169->regs + PHYAR);
[f300523]1182 async_usleep(20);
[727e639]1183 } while ((phyar & PHYAR_RW_WRITE) == 0);
1184
1185 return phyar & PHYAR_DATA_MASK;
1186}
1187
1188static void rtl8169_mii_write(rtl8169_t *rtl8169, uint8_t addr, uint16_t value)
1189{
1190 uint32_t phyar;
1191
[3bacee1]1192 phyar = PHYAR_RW_WRITE |
1193 ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT) |
1194 (value & PHYAR_DATA_MASK);
[727e639]1195
1196 pio_write_32(rtl8169->regs + PHYAR, phyar);
1197
1198 do {
1199 phyar = pio_read_32(rtl8169->regs + PHYAR);
[f300523]1200 async_usleep(20);
[727e639]1201 } while ((phyar & PHYAR_RW_WRITE) != 0);
1202
[f300523]1203 async_usleep(20);
[727e639]1204}
1205
[fef725d]1206/** Main function of RTL8169 driver
1207*
1208 * Just initialize the driver structures and
1209 * put it into the device drivers interface
1210 */
1211int main(void)
1212{
[b7fd2a0]1213 errno_t rc = nic_driver_init(NAME);
[fef725d]1214 if (rc != EOK)
1215 return rc;
1216 nic_driver_implement(
[3bacee1]1217 &rtl8169_driver_ops, &rtl8169_dev_ops, &rtl8169_nic_iface);
[fef725d]1218
1219 ddf_log_init(NAME);
1220 ddf_msg(LVL_NOTE, "HelenOS RTL8169 driver started");
1221 return ddf_driver_main(&rtl8169_driver);
1222}
Note: See TracBrowser for help on using the repository browser.