#include <lunaix/device.h>
-#include <lunaix/generic/isrm.h>
#include <lunaix/syslog.h>
#include <lunaix/mm/mmio.h>
static DEFINE_LLIST(pci_ports);
+
static void
-uart_msi_irq_handler(const struct hart_state* hstate)
+uart_msi_irq_handler(irq_t irq, const struct hart_state* hstate)
{
- int vector;
struct uart16550* uart;
- vector = hart_vector_stamp(hstate);
- uart = (struct uart16550*)isrm_get_payload(hstate);
+ uart = irq_payload(irq, struct uart16550);
assert(uart);
- uart_handle_irq(vector, uart);
-}
-
-static void
-uart_intx_irq_handler(const struct hart_state* hstate)
-{
- int vector = hart_vector_stamp(hstate);
- uart_handle_irq_overlap(vector, &pci_ports);
-}
-
-static int
-pci16550_init(struct device_def* def)
-{
- return pci_bind_definition_all(pcidev_def(def));
+ uart_handle_irq(irq, uart);
}
static bool
-pci16650_check_compat(struct pci_device_def* def,
- struct pci_device* pcidev)
+pci16x50_check_compat(struct pci_probe* probe)
{
unsigned int classid;
- classid = pci_device_class(pcidev);
+ classid = pci_device_class(probe);
return (classid & 0xffff00) == PCI_DEVICE_16x50_UART;
}
-static int
-pci16650_binder(struct device_def* def, struct device* dev)
+int
+pci16x50_pci_register(struct device_def* def)
+{
+ return !pci_register_driver(def, pci16x50_check_compat);
+}
+
+int
+pci16x50_pci_create(struct device_def* def, morph_t* obj)
{
- int irq;
struct pci_base_addr* bar;
- struct pci_device* pcidev;
+ struct pci_probe* probe;
struct uart16550* uart;
struct serial_dev* sdev;
+ irq_t irq;
- pcidev = PCI_DEVICE(dev);
+ probe = changeling_reveal(obj, pci_probe_morpher);
pci_reg_t cmd = 0;
cmd = 0;
pci_cmd_set_msi(&cmd);
- bar = pci_device_bar(pcidev, i);
+ bar = pci_device_bar(probe, i);
if (bar->size == 0) {
continue;
}
-
+
if (!pci_bar_mmio_space(bar)) {
+#ifdef CONFIG_PCI_PMIO
pci_cmd_set_pmio(&cmd);
- pci_apply_command(pcidev, cmd);
+ pci_apply_command(probe, cmd);
uart = uart16x50_pmio_create(bar->start);
- }
- else {
+#else
+ WARN("plaform configured to not support pmio access.");
+ continue;
+#endif
+ } else
+ {
pci_cmd_set_mmio(&cmd);
- pci_apply_command(pcidev, cmd);
+ pci_apply_command(probe, cmd);
uart = uart16x50_mmio_create(bar->start, bar->size);
}
continue;
}
- if (pci_capability_msi(pcidev)) {
- irq = isrm_ivexalloc(uart_msi_irq_handler);
- isrm_set_payload(irq, __ptr(uart));
- pci_setup_msi(pcidev, irq);
- }
- else {
- irq = pci_intr_irq(pcidev);
- irq = isrm_bindirq(irq, uart_intx_irq_handler);
+ if (!pci_capability_msi(probe)) {
+ WARN("failed to fallback to legacy INTx: not supported.");
+ continue;
}
- INFO("base: 0x%x (%s), irq=%d (%s)",
+ sdev = uart_create_serial(uart, &def->class, &pci_ports, "PCI");
+
+ irq = pci_declare_msi_irq(uart_msi_irq_handler, probe);
+ irq_set_payload(irq, uart);
+ pci_assign_msi(probe, irq, NULL);
+
+ INFO("base: 0x%x (%s), %s",
bar->start,
pci_bar_mmio_space(bar) ? "mmio" : "pmio",
- irq,
- pci_capability_msi(pcidev) ? "msi" : "intx, re-routed");
+ pci_capability_msi(probe) ? "msi" : "intx, re-routed");
- uart->iv = irq;
+ uart->irq = irq;
- sdev = uart_create_serial(uart, &def->class, &pci_ports, "PCI");
- pci_bind_instance(pcidev, sdev);
+ pci_bind_instance(probe, sdev->dev);
}
return 0;
}
-
-static struct pci_device_def uart_pci_def = {
- .devdef = { .class = DEVCLASS(DEVIF_PCI, DEVFN_CHAR, DEV_UART16550),
- .name = "16550 UART (PCI/MMIO)",
- .init = pci16550_init,
- .bind = pci16650_binder },
- .test_compatibility = pci16650_check_compat
-};
-EXPORT_PCI_DEVICE(uart16550_pci, &uart_pci_def, load_onboot);
\ No newline at end of file