//------------------------------------------------------------------------------ tOplkError pciedrv_shutdown(void) { // Unregister PCI driver DEBUG_LVL_DRVINTF_TRACE("%s calling pci_unregister_driver()\n", __FUNCTION__); pci_unregister_driver(&oplkPcieDriver_l); return kErrorOk; }
//------------------------------------------------------------------------------ tOplkError zynqdrv_exit(void) { DEBUG_LVL_DRVINTF_TRACE("%s(): Calling platform_driver_unregister()\n", __func__); platform_driver_unregister(&pcpDriver_l); return kErrorOk; }
//------------------------------------------------------------------------------ static void removeOnePciDev(struct pci_dev* pPciDev_p) { UINT8 barCount = 0; tBarInfo* pBarInfo = NULL; if (pcieDrvInstance_l.pPciDev != pPciDev_p) { // Trying to remove unknown device BUG_ON(pcieDrvInstance_l.pPciDev != pPciDev_p); goto Exit; } // Remove interrupt handler if (pPciDev_p->irq != 0) free_irq(pPciDev_p->irq, pPciDev_p); // Disable Message Signaled Interrupt DEBUG_LVL_DRVINTF_TRACE("%s Disable MSI\n", __FUNCTION__); pci_disable_msi(pPciDev_p); // unmap controller's register space for (barCount = 0; barCount < OPLK_MAX_BAR_COUNT; barCount++) { pBarInfo = &pcieDrvInstance_l.aBarInfo[barCount]; if (pBarInfo->virtualAddr != (ULONG)NULL) { iounmap((void __iomem*)pBarInfo->virtualAddr); pBarInfo->virtualAddr = (ULONG)NULL; } } // disable the PCI device pci_disable_device(pPciDev_p); // release memory regions pci_release_regions(pPciDev_p); pcieDrvInstance_l.pPciDev = NULL; Exit: return; }
//------------------------------------------------------------------------------ static INT initOnePciDev(struct pci_dev* pPciDev_p, const struct pci_device_id* pId_p) { INT result = 0; UINT8 barCount = 0; tBarInfo* pBarInfo = NULL; UNUSED_PARAMETER(pId_p); if (pcieDrvInstance_l.pPciDev != NULL) { // This driver is already connected to a PCIe device DEBUG_LVL_DRVINTF_TRACE("%s device %s discarded\n", __FUNCTION__, pci_name(pPciDev_p)); result = -ENODEV; goto Exit; } pcieDrvInstance_l.pPciDev = pPciDev_p; // Enable the PCIe device DEBUG_LVL_DRVINTF_TRACE("%s enable device\n", __FUNCTION__); result = pci_enable_device(pPciDev_p); if (result != 0) { goto Exit; } DEBUG_LVL_DRVINTF_TRACE("%s request PCIe regions\n", __FUNCTION__); result = pci_request_regions(pPciDev_p, PLK_DRV_NAME); if (result != 0) { goto ExitFail; } // Ignoring whether or not any BAR is accessible for (barCount = 0; barCount < OPLK_MAX_BAR_COUNT; barCount++) { pBarInfo = &pcieDrvInstance_l.aBarInfo[barCount]; if (pBarInfo->virtualAddr != (ULONG)NULL) { // The instance is already present result = -EIO; goto ExitFail; } // Look for the MMIO BARs if ((pci_resource_flags(pPciDev_p, barCount) & IORESOURCE_MEM) == 0) { continue; } // get the size of this field pBarInfo->length = pci_resource_len(pPciDev_p, barCount); // $$: Add check for weird broken IO regions pBarInfo->virtualAddr = (ULONG)ioremap_nocache(pci_resource_start(pPciDev_p, barCount), pBarInfo->length); if (pBarInfo->virtualAddr == (ULONG)NULL) { // Remap of controller's register space failed result = -EIO; goto ExitFail; } pBarInfo->busAddr = (ULONG)pci_resource_start(pPciDev_p, barCount); DEBUG_LVL_DRVINTF_TRACE("%s() --> ioremap\n", __FUNCTION__); DEBUG_LVL_DRVINTF_TRACE("\tbar#\t%u\n", barCount); DEBUG_LVL_DRVINTF_TRACE("\tbarLen\t%lu\n", pBarInfo->length); DEBUG_LVL_DRVINTF_TRACE("\tbarMap\t0x%lX\n", pBarInfo->virtualAddr); DEBUG_LVL_DRVINTF_TRACE("\tbarPhy\t0x%lX\n", pBarInfo->busAddr); } // Enable PCI busmaster DEBUG_LVL_DRVINTF_TRACE("%s enable busmaster\n", __FUNCTION__); pci_set_master(pPciDev_p); // Enable msi DEBUG_LVL_DRVINTF_TRACE("Enable MSI\n"); result = pci_enable_msi(pPciDev_p); if (result != 0) { DEBUG_LVL_DRVINTF_TRACE("%s Could not enable MSI\n", __FUNCTION__); } // Install interrupt handler DEBUG_LVL_DRVINTF_TRACE("%s install interrupt handler\n", __FUNCTION__); result = request_irq(pPciDev_p->irq, pcieDrvIrqHandler, IRQF_SHARED, PLK_DRV_NAME, /* pPciDev_p->dev.name */ pPciDev_p); if (result != 0) { goto ExitFail; } goto Exit; ExitFail: removeOnePciDev(pPciDev_p); Exit: DEBUG_LVL_DRVINTF_TRACE("%s finished with %d\n", __FUNCTION__, result); return result; }
//------------------------------------------------------------------------------ static int initOnePlatformDev(struct platform_device* pDev_p) { INT result = 0; tIoMemRegions memId = 0; /* checking if Microblaze Reset pin number is valid */ if (!gpio_is_valid(MB_RESET_PIN)) { DEBUG_LVL_DRVINTF_TRACE("Microblaze Reset pin not valid\n"); result = -EIO; goto Exit; } gpio_request(MB_RESET_PIN, "Reset Button"); gpio_export(MB_RESET_PIN, false); gpio_direction_output(MB_RESET_PIN, MICROBLAZE_RESET); /* Reset Microblaze */ gpio_set_value(MB_RESET_PIN, MICROBLAZE_RESET); /* Wait for Microblaze to come out of reset */ msleep(500); if (pDev_p == NULL) { DEBUG_LVL_DRVINTF_TRACE("%s(): Device discarded\n", __func__); result = -ENODEV; goto ExitClean; } if (instance_l.pPlatformDev != NULL) { DEBUG_LVL_DRVINTF_TRACE("%s(): Device (%s) already registered\n", __func__, pDev_p->name); result = -ENODEV; goto ExitClean; } // Save the handle for the platform device instance_l.pPlatformDev = pDev_p; for (memId = 0; memId < kIoMemRegionLast; memId++) { tIoMemoryResource* pMemResource = &instance_l.aIoMemRes[memId]; DEBUG_LVL_DRVINTF_TRACE("%s(): IOMEM resource initialization...%s", __func__, ((memId == 0) ? "Common Memory" : "Shared Memory")); pMemResource->pResource = platform_get_resource(pDev_p, IORESOURCE_MEM, memId); if (pMemResource->pResource == NULL) { result = -ENODEV; goto ExitClean; } pMemResource->size = (pMemResource->pResource->end - pMemResource->pResource->start + 1); /* Mark the region exclusively for Zynq device */ if (!request_mem_region(pMemResource->pResource->start, pMemResource->size, PLK_DRV_NAME)) { DEBUG_LVL_DRVINTF_TRACE("Request memory region failed for %s \n", ((memId == 0) ? "Common Memory" : "Shared Memory")); result = -ENOMEM; goto ExitClean; } DEBUG_LVL_DRVINTF_TRACE("MEM_RESOURCE: Start 0x(%X), End 0x(%X) \n", pMemResource->pResource->start, pMemResource->pResource->end); /* Remap Io memory regions into Linux virtual address space */ pMemResource->pBase = ioremap(pMemResource->pResource->start, pMemResource->size); if (pMemResource->pBase == NULL) { DEBUG_LVL_DRVINTF_TRACE("Ioremap failed for %s\n", ((memId == 0) ? "Common Memory" : "Shared Memory")); result = -EIO; goto ExitClean; } } DEBUG_LVL_DRVINTF_TRACE("%s(): IRQ resource initialization...", __func__); /* Get Interrupt resource for device */ instance_l.irqResource.pResource = platform_get_resource(pDev_p, IORESOURCE_IRQ, 0); if (instance_l.irqResource.pResource == NULL) { DEBUG_LVL_DRVINTF_TRACE("Failed\n"); result = -ENODEV; goto ExitClean; } /* Request IRQ */ DEBUG_LVL_DRVINTF_TRACE("Requesting IRQ resource..."); if (request_irq(instance_l.irqResource.pResource->start, pcpIrqHandler, 0, PLK_DRV_NAME, pDev_p)) { DEBUG_LVL_DRVINTF_TRACE("Request IRQ failed \n"); result = -EIO; goto ExitClean; } instance_l.irqResource.irqNumber = instance_l.irqResource.pResource->start; Exit: DEBUG_LVL_DRVINTF_TRACE("%s(): finished with %d\n", __func__, result); return result; ExitClean: DEBUG_LVL_DRVINTF_TRACE("%s(): finished with %d\n", __func__, result); removeOnePlatformDev(pDev_p); return result; }