source: mainline/uspace/drv/nic/rtl8169/driver.c

Last change on this file was 870841cf, checked in by Jiri Svoboda <jiri@…>, 5 months ago

Style issues related to improper use of 'inline' keyword.

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