source: mainline/uspace/drv/nic/rtl8169/driver.c@ 5ef16903

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 5ef16903 was a35b458, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

style: Remove trailing whitespace on _all_ lines, including empty ones, for particular file types.

Command used: tools/srepl '\s\+$' '' -- *.c *.h *.py *.sh *.s *.S *.ag

Currently, whitespace on empty lines is very inconsistent.
There are two basic choices: Either remove the whitespace, or keep empty lines
indented to the level of surrounding code. The former is AFAICT more common,
and also much easier to do automatically.

Alternatively, we could write script for automatic indentation, and use that
instead. However, if such a script exists, it's possible to use the indented
style locally, by having the editor apply relevant conversions on load/save,
without affecting remote repository. IMO, it makes more sense to adopt
the simpler rule.

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