File indexing completed on 2025-05-11 08:24:20
0001
0002
0003
0004
0005
0006
0007
0008
0009
0010
0011
0012
0013
0014
0015
0016
0017
0018
0019
0020
0021
0022
0023
0024
0025
0026
0027
0028
0029
0030
0031
0032
0033
0034
0035
0036
0037
0038
0039
0040
0041
0042
0043 #define USE_PCI_CFG_LIB
0044
0045
0046 #define PCIBUS_INFO
0047
0048 #include <inttypes.h>
0049 #include <stdlib.h>
0050 #include <stdio.h>
0051 #include <string.h>
0052
0053 #include <pci.h>
0054 #ifdef USE_PCI_CFG_LIB
0055 #include <pci/cfg.h>
0056 #endif
0057 #include <pci/irq.h>
0058
0059 #include <drvmgr/drvmgr.h>
0060 #include <drvmgr/pci_bus.h>
0061
0062 #ifdef DEBUG
0063 #define DBG(args...) printk(args)
0064 #else
0065 #define DBG(args...)
0066 #endif
0067
0068 int pcibus_bus_init1(struct drvmgr_bus *bus);
0069 int pcibus_unite(struct drvmgr_drv *drv, struct drvmgr_dev *dev);
0070 int pcibus_int_register(
0071 struct drvmgr_dev *dev,
0072 int index,
0073 const char *info,
0074 drvmgr_isr isr,
0075 void *arg);
0076 int pcibus_int_unregister(
0077 struct drvmgr_dev *dev,
0078 int index,
0079 drvmgr_isr isr,
0080 void *arg);
0081 int pcibus_int_clear(
0082 struct drvmgr_dev *dev,
0083 int index);
0084 static int pcibus_get_freq(
0085 struct drvmgr_dev *dev,
0086 int options,
0087 unsigned int *freq_hz);
0088
0089 int pcibus_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params);
0090
0091 void pcibus_dev_info(
0092 struct drvmgr_dev *dev,
0093 void (*print_line)(void *p, char *str),
0094 void *p);
0095
0096 struct drvmgr_bus_ops pcibus_ops = {
0097 .init = {
0098 pcibus_bus_init1,
0099 NULL,
0100 NULL,
0101 NULL
0102 },
0103 .remove = NULL,
0104 .unite = pcibus_unite,
0105 .int_register = pcibus_int_register,
0106 .int_unregister = pcibus_int_unregister,
0107 #if 0
0108 .int_enable = pcibus_int_enable,
0109 .int_disable = pcibus_int_disable,
0110 #endif
0111 .int_clear = pcibus_int_clear,
0112 .int_mask = NULL,
0113 .int_unmask = NULL,
0114 .get_params = pcibus_get_params,
0115 .get_freq = pcibus_get_freq,
0116 #ifdef PCIBUS_INFO
0117 .get_info_dev = pcibus_dev_info,
0118 #endif
0119 };
0120
0121 struct drvmgr_func pcibus_funcs[] = {
0122 DRVMGR_FUNC(PCI_FUNC_MREG_R8, NULL),
0123 DRVMGR_FUNC(PCI_FUNC_MREG_R16, NULL),
0124 DRVMGR_FUNC(PCI_FUNC_MREG_R32, NULL),
0125 DRVMGR_FUNC(PCI_FUNC_MREG_W8, NULL),
0126 DRVMGR_FUNC(PCI_FUNC_MREG_W16, NULL),
0127 DRVMGR_FUNC(PCI_FUNC_MREG_W32, NULL),
0128 DRVMGR_FUNC_END
0129 };
0130
0131
0132
0133
0134
0135 struct drvmgr_bus_res pcibus_drv_resources __attribute__((weak)) = {
0136 .next = NULL,
0137 .resource = {
0138 DRVMGR_RES_EMPTY,
0139 },
0140 };
0141
0142 struct pcibus_priv {
0143 struct drvmgr_dev *dev;
0144 };
0145
0146 static int compatible(struct pci_dev_id *id, struct pci_dev_id_match *drv)
0147 {
0148 if (((drv->vendor==PCI_ID_ANY) || (id->vendor==drv->vendor)) &&
0149 ((drv->device==PCI_ID_ANY) || (id->device==drv->device)) &&
0150 ((drv->subvendor==PCI_ID_ANY) || (id->subvendor==drv->subvendor)) &&
0151 ((drv->subdevice==PCI_ID_ANY) || (id->subdevice==drv->subdevice)) &&
0152 ((id->class & drv->class_mask) == drv->class))
0153 return 1;
0154 else
0155 return 0;
0156 }
0157
0158 int pcibus_unite(struct drvmgr_drv *drv,
0159 struct drvmgr_dev *dev)
0160 {
0161 struct pci_drv_info *pdrv;
0162 struct pci_dev_id_match *drvid;
0163 struct pci_dev_info *pci;
0164
0165 if (!drv || !dev || !dev->parent)
0166 return 0;
0167
0168 if ((drv->bus_type != DRVMGR_BUS_TYPE_PCI) ||
0169 (dev->parent->bus_type != DRVMGR_BUS_TYPE_PCI))
0170 return 0;
0171
0172 pci = (struct pci_dev_info *)dev->businfo;
0173 if (!pci)
0174 return 0;
0175
0176 pdrv = (struct pci_drv_info *)drv;
0177 drvid = pdrv->ids;
0178 if (!drvid)
0179 return 0;
0180 while (drvid->vendor != 0) {
0181 if (compatible(&pci->id, drvid)) {
0182
0183 DBG("DRV %p and DEV %p united\n", drv, dev);
0184 return 1;
0185 }
0186 drvid++;
0187 }
0188
0189 return 0;
0190 }
0191
0192 static int pcibus_int_get(struct drvmgr_dev *dev, int index)
0193 {
0194 int irq;
0195
0196
0197 if (index > 0) {
0198
0199 return -1;
0200 } else if (index == 0) {
0201
0202
0203
0204 irq = ((struct pci_dev_info *)dev->businfo)->irq;
0205 if (irq <= 0)
0206 return -1;
0207 } else {
0208
0209 irq = -index;
0210 }
0211 return irq;
0212 }
0213
0214
0215 int pcibus_int_register(
0216 struct drvmgr_dev *dev,
0217 int index,
0218 const char *info,
0219 drvmgr_isr isr,
0220 void *arg)
0221 {
0222 #ifdef DEBUG
0223 struct drvmgr_dev *busdev = dev->parent->dev;
0224 #endif
0225 int irq;
0226
0227
0228 irq = pcibus_int_get(dev, index);
0229 if (irq < 0)
0230 return -1;
0231
0232 DBG("Register PCI interrupt on %p for dev %p (IRQ: %d)\n",
0233 busdev, dev, irq);
0234
0235 return pci_interrupt_register(irq, info, isr, arg);
0236 }
0237
0238
0239 int pcibus_int_unregister(
0240 struct drvmgr_dev *dev,
0241 int index,
0242 drvmgr_isr isr,
0243 void *arg)
0244 {
0245 #ifdef DEBUG
0246 struct drvmgr_dev *busdev = dev->parent->dev;
0247 #endif
0248 int irq;
0249
0250
0251 irq = pcibus_int_get(dev, index);
0252 if (irq < 0)
0253 return -1;
0254
0255 DBG("Unregister PCI interrupt on %p for dev %p (IRQ: %d)\n",
0256 busdev, dev, irq);
0257
0258 return pci_interrupt_unregister(irq, isr, arg);
0259 }
0260
0261
0262 int pcibus_int_clear(
0263 struct drvmgr_dev *dev,
0264 int index)
0265 {
0266 int irq;
0267
0268
0269 irq = pcibus_int_get(dev, index);
0270 if (irq < 0)
0271 return -1;
0272
0273 pci_interrupt_clear(irq);
0274
0275 return 0;
0276 }
0277
0278 static int pcibus_get_freq(
0279 struct drvmgr_dev *dev,
0280 int options,
0281 unsigned int *freq_hz)
0282 {
0283
0284 *freq_hz = 33000000;
0285 return 0;
0286 }
0287
0288 int pcibus_get_params(struct drvmgr_dev *dev, struct drvmgr_bus_params *params)
0289 {
0290
0291 params->dev_prefix = NULL;
0292
0293 return 0;
0294 }
0295
0296 #ifdef PCIBUS_INFO
0297 void pcibus_dev_info(
0298 struct drvmgr_dev *dev,
0299 void (*print_line)(void *p, char *str),
0300 void *p)
0301 {
0302 struct pci_dev_info *devinfo;
0303 struct pcibus_res *pcibusres;
0304 struct pci_res *res;
0305 char buf[64];
0306 int i;
0307 char *str1, *res_types[3] = {" IO16", "MEMIO", " MEM"};
0308 uint32_t pcistart;
0309
0310 if (!dev)
0311 return;
0312
0313 devinfo = (struct pci_dev_info *)dev->businfo;
0314 if (!devinfo)
0315 return;
0316
0317 if ((devinfo->id.class >> 8) == PCID_PCI2PCI_BRIDGE)
0318 print_line(p, "PCI BRIDGE DEVICE");
0319 else
0320 print_line(p, "PCI DEVICE");
0321 sprintf(buf, "LOCATION: BUS:SLOT:FUNCTION [%x:%x:%x]",
0322 PCI_DEV_EXPAND(devinfo->pcidev));
0323 print_line(p, buf);
0324 sprintf(buf, "PCIID 0x%" PRIx16 "", devinfo->pcidev);
0325 print_line(p, buf);
0326 sprintf(buf, "VENDOR ID: %04x", devinfo->id.vendor);
0327 print_line(p, buf);
0328 sprintf(buf, "DEVICE ID: %04x", devinfo->id.device);
0329 print_line(p, buf);
0330 sprintf(buf, "SUBVEN ID: %04x", devinfo->id.subvendor);
0331 print_line(p, buf);
0332 sprintf(buf, "SUBDEV ID: %04x", devinfo->id.subdevice);
0333 print_line(p, buf);
0334 sprintf(buf, "CLASS: %" PRIx32, devinfo->id.class);
0335 print_line(p, buf);
0336 sprintf(buf, "REVISION: %x", devinfo->rev);
0337 print_line(p, buf);
0338 sprintf(buf, "IRQ: %d", devinfo->irq);
0339 print_line(p, buf);
0340 sprintf(buf, "PCIDEV ptr: %p", devinfo->pci_device);
0341 print_line(p, buf);
0342
0343
0344 print_line(p, "RESOURCES");
0345 for (i = 0; i < PCIDEV_RES_CNT; i++) {
0346 pcibusres = &devinfo->resources[i];
0347
0348 str1 = " RES";
0349 pcistart = -1;
0350 res = pcibusres->res;
0351 if (res && (res->flags & PCI_RES_TYPE_MASK)) {
0352 str1 = res_types[(res->flags & PCI_RES_TYPE_MASK) - 1];
0353 if (res->flags & PCI_RES_IO32)
0354 str1 = " IO32";
0355 pcistart = res->start;
0356 }
0357
0358 if (res && (res->flags & PCI_RES_FAIL)) {
0359 sprintf(buf, " %s[%d]: NOT ASSIGNED", str1, i);
0360 print_line(p, buf);
0361 continue;
0362 }
0363 if (!pcibusres->size)
0364 continue;
0365
0366 sprintf(buf, " %s[%d]: %08" PRIx32 "-%08" PRIx32
0367 " [PCIADR %" PRIx32 "]",
0368 str1, i, pcibusres->address,
0369 pcibusres->address + pcibusres->size - 1, pcistart);
0370 print_line(p, buf);
0371 }
0372 }
0373 #endif
0374
0375 #ifdef USE_PCI_CFG_LIB
0376
0377 static int pcibus_dev_register(struct pci_dev *dev, void *arg)
0378 {
0379 struct drvmgr_bus *pcibus = arg;
0380 struct drvmgr_dev *newdev;
0381 struct pci_dev_info *pciinfo;
0382 int i, type;
0383 struct pcibus_res *pcibusres;
0384 struct pci_res *pcires;
0385
0386 pci_dev_t pcidev = dev->busdevfun;
0387
0388 DBG("PCI DEV REGISTER: %x:%x:%x\n", PCI_DEV_EXPAND(pcidev));
0389
0390
0391 drvmgr_alloc_dev(&newdev, 24 + sizeof(struct pci_dev_info));
0392 newdev->next = NULL;
0393 newdev->parent = pcibus;
0394 newdev->minor_drv = 0;
0395 newdev->minor_bus = 0;
0396 newdev->priv = NULL;
0397 newdev->drv = NULL;
0398 newdev->name = (char *)(newdev + 1);
0399 newdev->next_in_drv = NULL;
0400 newdev->bus = NULL;
0401
0402
0403 pciinfo = (struct pci_dev_info *)((char *)(newdev + 1) + 24);
0404
0405
0406 pciinfo->id.vendor = dev->vendor;
0407 pciinfo->id.device = dev->device;
0408 pciinfo->id.subvendor = dev->subvendor;
0409 pciinfo->id.subdevice = dev->subdevice;
0410 pciinfo->rev = dev->classrev & 0xff;
0411 pciinfo->id.class = (dev->classrev >> 8) & 0xffffff;
0412
0413
0414 pciinfo->irq = dev->sysirq;
0415
0416
0417 pciinfo->pcidev = pcidev;
0418
0419
0420 pciinfo->pci_device = dev;
0421
0422
0423
0424
0425
0426 for (i = 0; i < PCIDEV_RES_CNT; i++) {
0427 pcibusres = &pciinfo->resources[i];
0428 pcires = &dev->resources[i];
0429 type = pcires->flags & PCI_RES_TYPE_MASK;
0430 if (type == 0 || (pcires->flags & PCI_RES_FAIL))
0431 continue;
0432
0433 pcibusres->address = pcires->start;
0434 if (pci_pci2cpu(&pcibusres->address, type))
0435 continue;
0436 pcibusres->res = pcires;
0437 pcibusres->size = pcires->end - pcires->start;
0438 }
0439
0440
0441 newdev->businfo = (void *)pciinfo;
0442
0443
0444 sprintf(newdev->name, "PCI_%x:%x:%x_%04x:%04x",
0445 PCI_DEV_BUS(pcidev), PCI_DEV_SLOT(pcidev), PCI_DEV_FUNC(pcidev),
0446 pciinfo->id.vendor, pciinfo->id.device);
0447
0448
0449 drvmgr_dev_register(newdev);
0450
0451 return 0;
0452 }
0453
0454 #else
0455
0456 static int pcibus_dev_register(pci_dev_t pcidev, void *arg)
0457 {
0458 struct drvmgr_bus *pcibus = arg;
0459 struct drvmgr_dev *newdev;
0460 struct pci_dev_info *pciinfo;
0461
0462 DBG("PCI DEV REGISTER: %x:%x:%x\n", PCI_DEV_EXPAND(pcidev));
0463
0464
0465 drvmgr_alloc_dev(&newdev, 24 + sizeof(struct pci_dev_info));
0466 newdev->next = NULL;
0467 newdev->parent = pcibus;
0468 newdev->minor_drv = 0;
0469 newdev->minor_bus = 0;
0470 newdev->priv = NULL;
0471 newdev->drv = NULL;
0472 newdev->name = (char *)(newdev + 1);
0473 newdev->next_in_drv = NULL;
0474 newdev->bus = NULL;
0475
0476
0477 pciinfo = (struct pci_dev_info *)((char *)(newdev + 1) + 24);
0478
0479
0480 pci_cfg_r16(pcidev, PCIR_VENDOR, &pciinfo->id.vendor);
0481 pci_cfg_r16(pcidev, PCIR_DEVICE, &pciinfo->id.device);
0482 pci_cfg_r32(pcidev, PCIR_REVID, &pciinfo->id.class);
0483 pciinfo->rev = pciinfo->id.class & 0xff;
0484 pciinfo->id.class = pciinfo->id.class >> 8;
0485
0486
0487 if ((pciinfo->id.class >> 8) != PCID_PCI2PCI_BRIDGE) {
0488 pci_cfg_r16(pcidev, PCIR_SUBVEND_0,
0489 &pciinfo->id.subvendor);
0490 pci_cfg_r16(pcidev, PCIR_SUBDEV_0, &pciinfo->id.subdevice);
0491 } else {
0492 pciinfo->id.subvendor = 0;
0493 pciinfo->id.subdevice = 0;
0494 }
0495
0496
0497 pci_cfg_r8(pcidev, PCIR_INTLINE, &pciinfo->irq);
0498
0499
0500 pciinfo->pcidev = pcidev;
0501
0502
0503 pciinfo->pci_device = NULL;
0504
0505
0506 newdev->businfo = (void *)pciinfo;
0507
0508
0509 sprintf(newdev->name, "PCI_%d:%d:%d_%04x:%04x",
0510 PCI_DEV_BUS(pcidev), PCI_DEV_SLOT(pcidev), PCI_DEV_FUNC(pcidev),
0511 pciinfo->id.vendor, pciinfo->id.device);
0512
0513
0514 drvmgr_dev_register(newdev);
0515
0516 return 0;
0517 }
0518
0519 #endif
0520
0521
0522 static int pcibus_devs_register(struct drvmgr_bus *bus)
0523 {
0524
0525 #ifdef USE_PCI_CFG_LIB
0526
0527 return pci_for_each_dev(pcibus_dev_register, bus);
0528 #else
0529
0530 return pci_for_each(pcibus_dev_register, bus);
0531 #endif
0532 }
0533
0534
0535
0536 int pcibus_register(struct drvmgr_dev *dev, struct pcibus_config *config)
0537 {
0538 struct pcibus_priv *priv;
0539 int i, fid, rc;
0540
0541 DBG("PCI BUS: initializing\n");
0542
0543
0544 drvmgr_alloc_bus(&dev->bus, sizeof(struct pcibus_priv));
0545 dev->bus->bus_type = DRVMGR_BUS_TYPE_PCI;
0546 dev->bus->next = NULL;
0547 dev->bus->dev = dev;
0548 dev->bus->children = NULL;
0549 dev->bus->ops = &pcibus_ops;
0550 dev->bus->dev_cnt = 0;
0551 dev->bus->reslist = NULL;
0552 dev->bus->maps_up = config->maps_up;
0553 dev->bus->maps_down = config->maps_down;
0554 dev->bus->funcs = &pcibus_funcs[0];
0555
0556
0557 for (i=0; i<6; i++) {
0558 fid = pcibus_funcs[i].funcid;
0559 rc = pci_access_func(RW_DIR(fid), RW_SIZE(fid),
0560 &pcibus_funcs[i].func, PCI_LITTLE_ENDIAN, 3);
0561 if (rc != 0)
0562 DBG("PCI BUS: MEMREG 0x%x function not defined\n", fid);
0563 }
0564
0565
0566 if (pcibus_drv_resources.resource[0].drv_id != 0)
0567 drvmgr_bus_res_add(dev->bus, &pcibus_drv_resources);
0568
0569
0570 priv = (struct pcibus_priv *)(dev->bus + 1);
0571 dev->bus->priv = priv;
0572
0573
0574 drvmgr_bus_register(dev->bus);
0575
0576 return DRVMGR_OK;
0577 }
0578
0579
0580
0581 int pcibus_bus_init1(struct drvmgr_bus *bus)
0582 {
0583 return pcibus_devs_register(bus);
0584 }