source: mainline/uspace/drv/bus/pci/pciintel/pci.c@ 3e6a98c5

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

Standards-compliant boolean type.

  • Property mode set to 100644
File size: 20.0 KB
Line 
1/*
2 * Copyright (c) 2010 Lenka Trochtova
3 * Copyright (c) 2011 Jiri Svoboda
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/**
31 * @defgroup pciintel pci bus driver for intel method 1.
32 * @brief HelenOS root pci bus driver for intel method 1.
33 * @{
34 */
35
36/** @file
37 */
38
39#include <assert.h>
40#include <byteorder.h>
41#include <stdio.h>
42#include <errno.h>
43#include <stdbool.h>
44#include <fibril_synch.h>
45#include <str.h>
46#include <ctype.h>
47#include <macros.h>
48#include <str_error.h>
49
50#include <ddf/driver.h>
51#include <ddf/log.h>
52#include <ipc/dev_iface.h>
53#include <ipc/irc.h>
54#include <ns.h>
55#include <ipc/services.h>
56#include <sysinfo.h>
57#include <ops/hw_res.h>
58#include <device/hw_res.h>
59#include <ddi.h>
60#include <pci_dev_iface.h>
61
62#include "pci.h"
63
64#define NAME "pciintel"
65
66#define CONF_ADDR(bus, dev, fn, reg) \
67 ((1 << 31) | (bus << 16) | (dev << 11) | (fn << 8) | (reg & ~3))
68
69/** Obtain PCI function soft-state from DDF function node */
70static pci_fun_t *pci_fun(ddf_fun_t *fnode)
71{
72 return ddf_fun_data_get(fnode);
73}
74
75/** Obtain PCI bus soft-state from DDF device node */
76#if 0
77static pci_bus_t *pci_bus(ddf_dev_t *dnode)
78{
79 return ddf_dev_data_get(dnode);
80}
81#endif
82
83/** Obtain PCI bus soft-state from function soft-state */
84static pci_bus_t *pci_bus_from_fun(pci_fun_t *fun)
85{
86 return fun->busptr;
87}
88
89/** Max is 47, align to something nice. */
90#define ID_MAX_STR_LEN 50
91
92static hw_resource_list_t *pciintel_get_resources(ddf_fun_t *fnode)
93{
94 pci_fun_t *fun = pci_fun(fnode);
95
96 if (fun == NULL)
97 return NULL;
98 return &fun->hw_resources;
99}
100
101static bool pciintel_enable_interrupt(ddf_fun_t *fnode)
102{
103 /* This is an old ugly way */
104 assert(fnode);
105 pci_fun_t *dev_data = pci_fun(fnode);
106
107 sysarg_t apic;
108 sysarg_t i8259;
109
110 async_sess_t *irc_sess = NULL;
111
112 if (((sysinfo_get_value("apic", &apic) == EOK) && (apic))
113 || ((sysinfo_get_value("i8259", &i8259) == EOK) && (i8259))) {
114 irc_sess = service_connect_blocking(EXCHANGE_SERIALIZE,
115 SERVICE_IRC, 0, 0);
116 }
117
118 if (!irc_sess)
119 return false;
120
121 size_t i = 0;
122 hw_resource_list_t *res = &dev_data->hw_resources;
123 for (; i < res->count; i++) {
124 if (res->resources[i].type == INTERRUPT) {
125 const int irq = res->resources[i].res.interrupt.irq;
126
127 async_exch_t *exch = async_exchange_begin(irc_sess);
128 const int rc =
129 async_req_1_0(exch, IRC_ENABLE_INTERRUPT, irq);
130 async_exchange_end(exch);
131
132 if (rc != EOK) {
133 async_hangup(irc_sess);
134 return false;
135 }
136 }
137 }
138
139 async_hangup(irc_sess);
140 return true;
141}
142
143static int pci_config_space_write_32(ddf_fun_t *fun, uint32_t address,
144 uint32_t data)
145{
146 if (address > 252)
147 return EINVAL;
148 pci_conf_write_32(pci_fun(fun), address, data);
149 return EOK;
150}
151
152static int pci_config_space_write_16(
153 ddf_fun_t *fun, uint32_t address, uint16_t data)
154{
155 if (address > 254)
156 return EINVAL;
157 pci_conf_write_16(pci_fun(fun), address, data);
158 return EOK;
159}
160
161static int pci_config_space_write_8(
162 ddf_fun_t *fun, uint32_t address, uint8_t data)
163{
164 if (address > 255)
165 return EINVAL;
166 pci_conf_write_8(pci_fun(fun), address, data);
167 return EOK;
168}
169
170static int pci_config_space_read_32(
171 ddf_fun_t *fun, uint32_t address, uint32_t *data)
172{
173 if (address > 252)
174 return EINVAL;
175 *data = pci_conf_read_32(pci_fun(fun), address);
176 return EOK;
177}
178
179static int pci_config_space_read_16(
180 ddf_fun_t *fun, uint32_t address, uint16_t *data)
181{
182 if (address > 254)
183 return EINVAL;
184 *data = pci_conf_read_16(pci_fun(fun), address);
185 return EOK;
186}
187
188static int pci_config_space_read_8(
189 ddf_fun_t *fun, uint32_t address, uint8_t *data)
190{
191 if (address > 255)
192 return EINVAL;
193 *data = pci_conf_read_8(pci_fun(fun), address);
194 return EOK;
195}
196
197static hw_res_ops_t pciintel_hw_res_ops = {
198 .get_resource_list = &pciintel_get_resources,
199 .enable_interrupt = &pciintel_enable_interrupt,
200};
201
202static pci_dev_iface_t pci_dev_ops = {
203 .config_space_read_8 = &pci_config_space_read_8,
204 .config_space_read_16 = &pci_config_space_read_16,
205 .config_space_read_32 = &pci_config_space_read_32,
206 .config_space_write_8 = &pci_config_space_write_8,
207 .config_space_write_16 = &pci_config_space_write_16,
208 .config_space_write_32 = &pci_config_space_write_32
209};
210
211static ddf_dev_ops_t pci_fun_ops = {
212 .interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops,
213 .interfaces[PCI_DEV_IFACE] = &pci_dev_ops
214};
215
216static int pci_dev_add(ddf_dev_t *);
217static int pci_fun_online(ddf_fun_t *);
218static int pci_fun_offline(ddf_fun_t *);
219
220/** PCI bus driver standard operations */
221static driver_ops_t pci_ops = {
222 .dev_add = &pci_dev_add,
223 .fun_online = &pci_fun_online,
224 .fun_offline = &pci_fun_offline,
225};
226
227/** PCI bus driver structure */
228static driver_t pci_driver = {
229 .name = NAME,
230 .driver_ops = &pci_ops
231};
232
233static void pci_conf_read(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
234{
235 pci_bus_t *bus = pci_bus_from_fun(fun);
236
237 fibril_mutex_lock(&bus->conf_mutex);
238
239 const uint32_t conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
240 void *addr = bus->conf_data_port + (reg & 3);
241
242 pio_write_32(bus->conf_addr_port, host2uint32_t_le(conf_addr));
243
244 switch (len) {
245 case 1:
246 /* No endianness change for 1 byte */
247 buf[0] = pio_read_8(addr);
248 break;
249 case 2:
250 ((uint16_t *) buf)[0] = uint16_t_le2host(pio_read_16(addr));
251 break;
252 case 4:
253 ((uint32_t *) buf)[0] = uint32_t_le2host(pio_read_32(addr));
254 break;
255 }
256
257 fibril_mutex_unlock(&bus->conf_mutex);
258}
259
260static void pci_conf_write(pci_fun_t *fun, int reg, uint8_t *buf, size_t len)
261{
262 pci_bus_t *bus = pci_bus_from_fun(fun);
263
264 fibril_mutex_lock(&bus->conf_mutex);
265
266 const uint32_t conf_addr = CONF_ADDR(fun->bus, fun->dev, fun->fn, reg);
267 void *addr = bus->conf_data_port + (reg & 3);
268
269 pio_write_32(bus->conf_addr_port, host2uint32_t_le(conf_addr));
270
271 switch (len) {
272 case 1:
273 /* No endianness change for 1 byte */
274 pio_write_8(addr, buf[0]);
275 break;
276 case 2:
277 pio_write_16(addr, host2uint16_t_le(((uint16_t *) buf)[0]));
278 break;
279 case 4:
280 pio_write_32(addr, host2uint32_t_le(((uint32_t *) buf)[0]));
281 break;
282 }
283
284 fibril_mutex_unlock(&bus->conf_mutex);
285}
286
287uint8_t pci_conf_read_8(pci_fun_t *fun, int reg)
288{
289 uint8_t res;
290 pci_conf_read(fun, reg, &res, 1);
291 return res;
292}
293
294uint16_t pci_conf_read_16(pci_fun_t *fun, int reg)
295{
296 uint16_t res;
297 pci_conf_read(fun, reg, (uint8_t *) &res, 2);
298 return res;
299}
300
301uint32_t pci_conf_read_32(pci_fun_t *fun, int reg)
302{
303 uint32_t res;
304 pci_conf_read(fun, reg, (uint8_t *) &res, 4);
305 return res;
306}
307
308void pci_conf_write_8(pci_fun_t *fun, int reg, uint8_t val)
309{
310 pci_conf_write(fun, reg, (uint8_t *) &val, 1);
311}
312
313void pci_conf_write_16(pci_fun_t *fun, int reg, uint16_t val)
314{
315 pci_conf_write(fun, reg, (uint8_t *) &val, 2);
316}
317
318void pci_conf_write_32(pci_fun_t *fun, int reg, uint32_t val)
319{
320 pci_conf_write(fun, reg, (uint8_t *) &val, 4);
321}
322
323void pci_fun_create_match_ids(pci_fun_t *fun)
324{
325 int rc;
326 char match_id_str[ID_MAX_STR_LEN];
327
328 /* Vendor ID & Device ID, length(incl \0) 22 */
329 rc = snprintf(match_id_str, ID_MAX_STR_LEN, "pci/ven=%04x&dev=%04x",
330 fun->vendor_id, fun->device_id);
331 if (rc < 0) {
332 ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
333 str_error(rc));
334 }
335
336 rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 90);
337 if (rc != EOK) {
338 ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
339 }
340
341 /* Class, subclass, prog IF, revision, length(incl \0) 47 */
342 rc = snprintf(match_id_str, ID_MAX_STR_LEN,
343 "pci/class=%02x&subclass=%02x&progif=%02x&revision=%02x",
344 fun->class_code, fun->subclass_code, fun->prog_if, fun->revision);
345 if (rc < 0) {
346 ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
347 str_error(rc));
348 }
349
350 rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 70);
351 if (rc != EOK) {
352 ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
353 }
354
355 /* Class, subclass, prog IF, length(incl \0) 35 */
356 rc = snprintf(match_id_str, ID_MAX_STR_LEN,
357 "pci/class=%02x&subclass=%02x&progif=%02x",
358 fun->class_code, fun->subclass_code, fun->prog_if);
359 if (rc < 0) {
360 ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
361 str_error(rc));
362 }
363
364 rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 60);
365 if (rc != EOK) {
366 ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
367 }
368
369 /* Class, subclass, length(incl \0) 25 */
370 rc = snprintf(match_id_str, ID_MAX_STR_LEN,
371 "pci/class=%02x&subclass=%02x",
372 fun->class_code, fun->subclass_code);
373 if (rc < 0) {
374 ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
375 str_error(rc));
376 }
377
378 rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 50);
379 if (rc != EOK) {
380 ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
381 }
382
383 /* Class, length(incl \0) 13 */
384 rc = snprintf(match_id_str, ID_MAX_STR_LEN, "pci/class=%02x",
385 fun->class_code);
386 if (rc < 0) {
387 ddf_msg(LVL_ERROR, "Failed creating match ID str: %s",
388 str_error(rc));
389 }
390
391 rc = ddf_fun_add_match_id(fun->fnode, match_id_str, 40);
392 if (rc != EOK) {
393 ddf_msg(LVL_ERROR, "Failed adding match ID: %s", str_error(rc));
394 }
395
396 /* TODO add subsys ids, but those exist only in header type 0 */
397}
398
399void pci_add_range(pci_fun_t *fun, uint64_t range_addr, size_t range_size,
400 bool io)
401{
402 hw_resource_list_t *hw_res_list = &fun->hw_resources;
403 hw_resource_t *hw_resources = hw_res_list->resources;
404 size_t count = hw_res_list->count;
405
406 assert(hw_resources != NULL);
407 assert(count < PCI_MAX_HW_RES);
408
409 if (io) {
410 hw_resources[count].type = IO_RANGE;
411 hw_resources[count].res.io_range.address = range_addr;
412 hw_resources[count].res.io_range.size = range_size;
413 hw_resources[count].res.io_range.endianness = LITTLE_ENDIAN;
414 } else {
415 hw_resources[count].type = MEM_RANGE;
416 hw_resources[count].res.mem_range.address = range_addr;
417 hw_resources[count].res.mem_range.size = range_size;
418 hw_resources[count].res.mem_range.endianness = LITTLE_ENDIAN;
419 }
420
421 hw_res_list->count++;
422}
423
424/** Read the base address register (BAR) of the device and if it contains valid
425 * address add it to the devices hw resource list.
426 *
427 * @param fun PCI function
428 * @param addr The address of the BAR in the PCI configuration address space of
429 * the device
430 * @return The addr the address of the BAR which should be read next
431 */
432int pci_read_bar(pci_fun_t *fun, int addr)
433{
434 /* Value of the BAR */
435 uint32_t val, mask;
436 /* IO space address */
437 bool io;
438 /* 64-bit wide address */
439 bool addrw64;
440
441 /* Size of the io or memory range specified by the BAR */
442 size_t range_size;
443 /* Beginning of the io or memory range specified by the BAR */
444 uint64_t range_addr;
445
446 /* Get the value of the BAR. */
447 val = pci_conf_read_32(fun, addr);
448
449#define IO_MASK (~0x3)
450#define MEM_MASK (~0xf)
451
452 io = (bool) (val & 1);
453 if (io) {
454 addrw64 = false;
455 mask = IO_MASK;
456 } else {
457 mask = MEM_MASK;
458 switch ((val >> 1) & 3) {
459 case 0:
460 addrw64 = false;
461 break;
462 case 2:
463 addrw64 = true;
464 break;
465 default:
466 /* reserved, go to the next BAR */
467 return addr + 4;
468 }
469 }
470
471 /* Get the address mask. */
472 pci_conf_write_32(fun, addr, 0xffffffff);
473 mask &= pci_conf_read_32(fun, addr);
474
475 /* Restore the original value. */
476 pci_conf_write_32(fun, addr, val);
477 val = pci_conf_read_32(fun, addr);
478
479 range_size = pci_bar_mask_to_size(mask);
480
481 if (addrw64) {
482 range_addr = ((uint64_t)pci_conf_read_32(fun, addr + 4) << 32) |
483 (val & 0xfffffff0);
484 } else {
485 range_addr = (val & 0xfffffff0);
486 }
487
488 if (range_addr != 0) {
489 ddf_msg(LVL_DEBUG, "Function %s : address = %" PRIx64
490 ", size = %x", ddf_fun_get_name(fun->fnode), range_addr,
491 (unsigned int) range_size);
492 }
493
494 pci_add_range(fun, range_addr, range_size, io);
495
496 if (addrw64)
497 return addr + 8;
498
499 return addr + 4;
500}
501
502void pci_add_interrupt(pci_fun_t *fun, int irq)
503{
504 hw_resource_list_t *hw_res_list = &fun->hw_resources;
505 hw_resource_t *hw_resources = hw_res_list->resources;
506 size_t count = hw_res_list->count;
507
508 assert(NULL != hw_resources);
509 assert(count < PCI_MAX_HW_RES);
510
511 hw_resources[count].type = INTERRUPT;
512 hw_resources[count].res.interrupt.irq = irq;
513
514 hw_res_list->count++;
515
516 ddf_msg(LVL_NOTE, "Function %s uses irq %x.", ddf_fun_get_name(fun->fnode), irq);
517}
518
519void pci_read_interrupt(pci_fun_t *fun)
520{
521 uint8_t irq = pci_conf_read_8(fun, PCI_BRIDGE_INT_LINE);
522 if (irq != 0xff)
523 pci_add_interrupt(fun, irq);
524}
525
526/** Enumerate (recursively) and register the devices connected to a pci bus.
527 *
528 * @param bus Host-to-PCI bridge
529 * @param bus_num Bus number
530 */
531void pci_bus_scan(pci_bus_t *bus, int bus_num)
532{
533 pci_fun_t *fun;
534 int rc;
535
536 int child_bus = 0;
537 int dnum, fnum;
538 bool multi;
539 uint8_t header_type;
540
541 for (dnum = 0; dnum < 32; dnum++) {
542 multi = true;
543 for (fnum = 0; multi && fnum < 8; fnum++) {
544 fun = pci_fun_new(bus);
545
546 pci_fun_init(fun, bus_num, dnum, fnum);
547 if (fun->vendor_id == 0xffff) {
548 pci_fun_delete(fun);
549 /*
550 * The device is not present, go on scanning the
551 * bus.
552 */
553 if (fnum == 0)
554 break;
555 else
556 continue;
557 }
558
559 header_type = pci_conf_read_8(fun, PCI_HEADER_TYPE);
560 if (fnum == 0) {
561 /* Is the device multifunction? */
562 multi = header_type >> 7;
563 }
564 /* Clear the multifunction bit. */
565 header_type = header_type & 0x7F;
566
567 char *fun_name = pci_fun_create_name(fun);
568 if (fun_name == NULL) {
569 ddf_msg(LVL_ERROR, "Out of memory.");
570 pci_fun_delete(fun);
571 return;
572 }
573
574 rc = ddf_fun_set_name(fun->fnode, fun_name);
575 free(fun_name);
576 if (rc != EOK) {
577 ddf_msg(LVL_ERROR, "Failed setting function name.");
578 pci_fun_delete(fun);
579 return;
580 }
581
582 pci_alloc_resource_list(fun);
583 pci_read_bars(fun);
584 pci_read_interrupt(fun);
585
586 ddf_fun_set_ops(fun->fnode, &pci_fun_ops);
587
588 ddf_msg(LVL_DEBUG, "Adding new function %s.",
589 ddf_fun_get_name(fun->fnode));
590
591 pci_fun_create_match_ids(fun);
592
593 if (ddf_fun_bind(fun->fnode) != EOK) {
594 pci_clean_resource_list(fun);
595 pci_fun_delete(fun);
596 continue;
597 }
598
599 if (header_type == PCI_HEADER_TYPE_BRIDGE ||
600 header_type == PCI_HEADER_TYPE_CARDBUS) {
601 child_bus = pci_conf_read_8(fun,
602 PCI_BRIDGE_SEC_BUS_NUM);
603 ddf_msg(LVL_DEBUG, "Device is pci-to-pci "
604 "bridge, secondary bus number = %d.",
605 bus_num);
606 if (child_bus > bus_num)
607 pci_bus_scan(bus, child_bus);
608 }
609 }
610 }
611}
612
613static int pci_dev_add(ddf_dev_t *dnode)
614{
615 pci_bus_t *bus = NULL;
616 ddf_fun_t *ctl = NULL;
617 bool got_res = false;
618 async_sess_t *sess;
619 int rc;
620
621 ddf_msg(LVL_DEBUG, "pci_dev_add");
622
623 bus = ddf_dev_data_alloc(dnode, sizeof(pci_bus_t));
624 if (bus == NULL) {
625 ddf_msg(LVL_ERROR, "pci_dev_add allocation failed.");
626 rc = ENOMEM;
627 goto fail;
628 }
629 fibril_mutex_initialize(&bus->conf_mutex);
630
631 bus->dnode = dnode;
632
633 sess = ddf_dev_parent_sess_create(dnode, EXCHANGE_SERIALIZE);
634 if (sess == NULL) {
635 ddf_msg(LVL_ERROR, "pci_dev_add failed to connect to the "
636 "parent driver.");
637 rc = ENOENT;
638 goto fail;
639 }
640
641 hw_resource_list_t hw_resources;
642
643 rc = hw_res_get_resource_list(sess, &hw_resources);
644 if (rc != EOK) {
645 ddf_msg(LVL_ERROR, "pci_dev_add failed to get hw resources "
646 "for the device.");
647 goto fail;
648 }
649 got_res = true;
650
651
652 assert(hw_resources.count > 1);
653 assert(hw_resources.resources[0].type == IO_RANGE);
654 assert(hw_resources.resources[0].res.io_range.size >= 4);
655
656 assert(hw_resources.resources[1].type == IO_RANGE);
657 assert(hw_resources.resources[1].res.io_range.size >= 4);
658
659 ddf_msg(LVL_DEBUG, "conf_addr = %" PRIx64 ".",
660 hw_resources.resources[0].res.io_range.address);
661 ddf_msg(LVL_DEBUG, "data_addr = %" PRIx64 ".",
662 hw_resources.resources[1].res.io_range.address);
663
664 bus->conf_io_addr =
665 (uint32_t) hw_resources.resources[0].res.io_range.address;
666 bus->conf_io_data =
667 (uint32_t) hw_resources.resources[1].res.io_range.address;
668
669 if (pio_enable((void *)(uintptr_t)bus->conf_io_addr, 4,
670 &bus->conf_addr_port)) {
671 ddf_msg(LVL_ERROR, "Failed to enable configuration ports.");
672 rc = EADDRNOTAVAIL;
673 goto fail;
674 }
675 if (pio_enable((void *)(uintptr_t)bus->conf_io_data, 4,
676 &bus->conf_data_port)) {
677 ddf_msg(LVL_ERROR, "Failed to enable configuration ports.");
678 rc = EADDRNOTAVAIL;
679 goto fail;
680 }
681
682 /* Make the bus device more visible. It has no use yet. */
683 ddf_msg(LVL_DEBUG, "Adding a 'ctl' function");
684
685 ctl = ddf_fun_create(bus->dnode, fun_exposed, "ctl");
686 if (ctl == NULL) {
687 ddf_msg(LVL_ERROR, "Failed creating control function.");
688 rc = ENOMEM;
689 goto fail;
690 }
691
692 rc = ddf_fun_bind(ctl);
693 if (rc != EOK) {
694 ddf_msg(LVL_ERROR, "Failed binding control function.");
695 goto fail;
696 }
697
698 /* Enumerate functions. */
699 ddf_msg(LVL_DEBUG, "Scanning the bus");
700 pci_bus_scan(bus, 0);
701
702 hw_res_clean_resource_list(&hw_resources);
703
704 return EOK;
705
706fail:
707 if (got_res)
708 hw_res_clean_resource_list(&hw_resources);
709
710 if (ctl != NULL)
711 ddf_fun_destroy(ctl);
712
713 return rc;
714}
715
716static int pci_fun_online(ddf_fun_t *fun)
717{
718 ddf_msg(LVL_DEBUG, "pci_fun_online()");
719 return ddf_fun_online(fun);
720}
721
722static int pci_fun_offline(ddf_fun_t *fun)
723{
724 ddf_msg(LVL_DEBUG, "pci_fun_offline()");
725 return ddf_fun_offline(fun);
726}
727
728static void pciintel_init(void)
729{
730 ddf_log_init(NAME);
731 pci_fun_ops.interfaces[HW_RES_DEV_IFACE] = &pciintel_hw_res_ops;
732 pci_fun_ops.interfaces[PCI_DEV_IFACE] = &pci_dev_ops;
733}
734
735pci_fun_t *pci_fun_new(pci_bus_t *bus)
736{
737 pci_fun_t *fun;
738 ddf_fun_t *fnode;
739
740 fnode = ddf_fun_create(bus->dnode, fun_inner, NULL);
741 if (fnode == NULL)
742 return NULL;
743
744 fun = ddf_fun_data_alloc(fnode, sizeof(pci_fun_t));
745 if (fun == NULL)
746 return NULL;
747
748 fun->busptr = bus;
749 fun->fnode = fnode;
750 return fun;
751}
752
753void pci_fun_init(pci_fun_t *fun, int bus, int dev, int fn)
754{
755 fun->bus = bus;
756 fun->dev = dev;
757 fun->fn = fn;
758 fun->vendor_id = pci_conf_read_16(fun, PCI_VENDOR_ID);
759 fun->device_id = pci_conf_read_16(fun, PCI_DEVICE_ID);
760 fun->class_code = pci_conf_read_8(fun, PCI_BASE_CLASS);
761 fun->subclass_code = pci_conf_read_8(fun, PCI_SUB_CLASS);
762 fun->prog_if = pci_conf_read_8(fun, PCI_PROG_IF);
763 fun->revision = pci_conf_read_8(fun, PCI_REVISION_ID);
764}
765
766void pci_fun_delete(pci_fun_t *fun)
767{
768 hw_res_clean_resource_list(&fun->hw_resources);
769 if (fun->fnode != NULL)
770 ddf_fun_destroy(fun->fnode);
771}
772
773char *pci_fun_create_name(pci_fun_t *fun)
774{
775 char *name = NULL;
776
777 asprintf(&name, "%02x:%02x.%01x", fun->bus, fun->dev,
778 fun->fn);
779 return name;
780}
781
782bool pci_alloc_resource_list(pci_fun_t *fun)
783{
784 fun->hw_resources.resources = fun->resources;
785 return true;
786}
787
788void pci_clean_resource_list(pci_fun_t *fun)
789{
790 fun->hw_resources.resources = NULL;
791}
792
793/** Read the base address registers (BARs) of the function and add the addresses
794 * to its HW resource list.
795 *
796 * @param fun PCI function
797 */
798void pci_read_bars(pci_fun_t *fun)
799{
800 /*
801 * Position of the BAR in the PCI configuration address space of the
802 * device.
803 */
804 int addr = PCI_BASE_ADDR_0;
805
806 while (addr <= PCI_BASE_ADDR_5)
807 addr = pci_read_bar(fun, addr);
808}
809
810size_t pci_bar_mask_to_size(uint32_t mask)
811{
812 size_t size = mask & ~(mask - 1);
813 return size;
814}
815
816int main(int argc, char *argv[])
817{
818 printf(NAME ": HelenOS PCI bus driver (Intel method 1).\n");
819 pciintel_init();
820 return ddf_driver_main(&pci_driver);
821}
822
823/**
824 * @}
825 */
Note: See TracBrowser for help on using the repository browser.