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

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since e6def65 was e6def65, checked in by Jan Vesely <jano.vesely@…>, 14 years ago

Use named initializers.

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