source: mainline/uspace/drv/pciintel/pci.c@ af6b5157

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

Split driver.h into ddf/driver.h and ddf/interrupt.h.

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