source: mainline/uspace/drv/nic/rtl8169/driver.c@ 1433ecda

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 1433ecda was eadaeae8, checked in by Jakub Jermar <jakub@…>, 8 years ago

Make capability handles type-safe

Define distinct pointer types for the handles of the supported
capability types and use them instead of integer handles. This makes it
virtually impossible to pass a non-handle or a handle of different type
instead of the proper handle. Also turn cap_handle_t into an "untyped"
capability handle that can be assigned to and from the "typed" handles.

This commit also fixes a bug in msim-con driver, which wrongly used the
IRQ number instead of the IRQ capability handle to unregister the IRQ.

This commit also fixes the wrong use of the capability handle instead
of error code in libusbhost.

  • 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,
315 rtl8169_on_activated, NULL, rtl8169_on_stopped);
316 nic_set_filtering_change_handlers(nic_data,
[0764cc8a]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
552 *duplex = phystatus & PHYSTATUS_FDX
553 ? NIC_CM_FULL_DUPLEX : NIC_CM_HALF_DUPLEX;
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
577 if (duplex != NIC_CM_HALF_DUPLEX && duplex != NIC_CM_FULL_DUPLEX)
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);
[320bd52]941 ddf_msg(LVL_DEBUG," new RCR value: 0x%08x", rcr);
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
1175 phyar = PHYAR_RW_READ
1176 | ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT);
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
1192 phyar = PHYAR_RW_WRITE
1193 | ((addr & PHYAR_ADDR_MASK) << PHYAR_ADDR_SHIFT)
1194 | (value & PHYAR_DATA_MASK);
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(
1217 &rtl8169_driver_ops, &rtl8169_dev_ops, &rtl8169_nic_iface);
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.