rt-thread-official/components/drivers/nvme/nvme-pci.c

172 lines
3.5 KiB
C

/*
* Copyright (c) 2006-2023, RT-Thread Development Team
*
* SPDX-License-Identifier: Apache-2.0
*
* Change Logs:
* Date Author Notes
* 2023-02-25 GuEe-GUI the first version
*/
#include <rtthread.h>
#include <rtdevice.h>
#define NVME_REG_BAR 0
struct pci_nvme_quirk
{
const struct rt_nvme_ops *ops;
};
struct pci_nvme_controller
{
struct rt_nvme_controller parent;
const struct pci_nvme_quirk *quirk;
rt_bool_t is_msi;
struct rt_pci_msix_entry msix_entries[RT_USING_NVME_QUEUE];
};
static const struct rt_nvme_ops pci_nvme_std_ops =
{
.name = "PCI",
};
static rt_err_t pci_nvme_probe(struct rt_pci_device *pdev)
{
rt_err_t err;
rt_ssize_t msi_nr;
struct rt_nvme_controller *nvme;
struct pci_nvme_controller *pci_nvme = rt_calloc(1, sizeof(*pci_nvme));
const struct pci_nvme_quirk *quirk = pdev->id->data;
if (!pci_nvme)
{
return -RT_ENOMEM;
}
pci_nvme->quirk = quirk;
nvme = &pci_nvme->parent;
nvme->dev = &pdev->parent;
nvme->regs = rt_pci_iomap(pdev, NVME_REG_BAR);
if (!nvme->regs)
{
err = -RT_EIO;
goto _fail;
}
nvme->ops = quirk && quirk->ops ? quirk->ops : &pci_nvme_std_ops;
if ((msi_nr = rt_pci_msix_vector_count(pdev)) <= 0)
{
msi_nr = rt_pci_msi_vector_count(pdev);
}
if (msi_nr > 0)
{
nvme->irqs_nr = RT_ARRAY_SIZE(pci_nvme->msix_entries);
nvme->irqs_nr = rt_min_t(rt_size_t, msi_nr, nvme->irqs_nr);
}
if (nvme->irqs_nr > 0)
{
rt_pci_msix_entry_index_linear(pci_nvme->msix_entries, nvme->irqs_nr);
if (rt_pci_msix_enable(pdev, pci_nvme->msix_entries, nvme->irqs_nr) > 0)
{
pci_nvme->is_msi = RT_TRUE;
for (int i = 0; i < nvme->irqs_nr; ++i)
{
nvme->irqs[i] = pci_nvme->msix_entries[i].irq;
}
}
}
if (!pci_nvme->is_msi)
{
nvme->irqs_nr = 1;
nvme->irqs[0] = pdev->irq;
rt_pci_irq_unmask(pdev);
}
rt_pci_set_master(pdev);
if ((err = rt_nvme_controller_register(nvme)))
{
goto _disable;
}
pdev->parent.user_data = pci_nvme;
return RT_EOK;
_disable:
if (pci_nvme->is_msi)
{
rt_pci_msix_disable(pdev);
}
else
{
rt_pci_irq_mask(pdev);
}
rt_pci_clear_master(pdev);
rt_iounmap(nvme->regs);
_fail:
rt_free(pci_nvme);
return err;
}
static rt_err_t pci_nvme_remove(struct rt_pci_device *pdev)
{
struct rt_nvme_controller *nvme;
struct pci_nvme_controller *pci_nvme = pdev->parent.user_data;
nvme = &pci_nvme->parent;
rt_nvme_controller_unregister(nvme);
if (pci_nvme->is_msi)
{
rt_pci_msix_disable(pdev);
}
else
{
/* INTx is shared, don't mask all */
rt_hw_interrupt_umask(pdev->irq);
rt_pci_irq_mask(pdev);
}
rt_pci_clear_master(pdev);
rt_iounmap(nvme->regs);
rt_free(pci_nvme);
return RT_EOK;
}
static rt_err_t pci_nvme_shutdown(struct rt_pci_device *pdev)
{
return pci_nvme_remove(pdev);
}
static const struct rt_pci_device_id pci_nvme_ids[] =
{
{ RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT, 0x0010) },
{ RT_PCI_DEVICE_CLASS(PCIS_STORAGE_EXPRESS, ~0) },
{ /* sentinel */ }
};
static struct rt_pci_driver pci_nvme_driver =
{
.name = "nvme-pci",
.ids = pci_nvme_ids,
.probe = pci_nvme_probe,
.remove = pci_nvme_remove,
.shutdown = pci_nvme_shutdown,
};
RT_PCI_DRIVER_EXPORT(pci_nvme_driver);