-
Notifications
You must be signed in to change notification settings - Fork 6
Implement RTL8139 Driver #81
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: trunk
Are you sure you want to change the base?
Changes from all commits
b5c3f13
be0542e
e004802
bdb392c
920cacf
b671632
a6caa17
ea0a5b9
b87a988
82dafa1
7bca143
e283fbd
379aee4
a948a91
cd8b408
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,9 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: ukoOS Contributors | ||
| * | ||
| * SPDX-License-Identifier: GPL-3.0-or-later | ||
| */ | ||
|
|
||
| #include <devices/netdev.h> | ||
|
|
||
| struct list_head netdevs = LIST_INIT(netdevs); |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,48 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: ukoOS Contributors | ||
| * | ||
| * SPDX-License-Identifier: GPL-3.0-or-later | ||
| */ | ||
|
|
||
| #include <devices/pci.h> | ||
|
|
||
| struct list_head pcis = LIST_INIT(pcis); | ||
|
|
||
| struct registered_device { | ||
| void (*callback)(struct pci *this, struct pci_regs *regs); | ||
| u16 vid; | ||
| u16 did; | ||
| }; | ||
|
|
||
| struct registered_device *handlers = nullptr; | ||
| usize handlers_len = 0, handlers_cap = 0; | ||
|
|
||
| void pci_register(u16 vid, u16 did, | ||
| void (*callback)(struct pci *this, struct pci_regs *regs)) { | ||
| if (!handlers) { | ||
| assert(!handlers_len); | ||
| handlers_cap = 16; | ||
| handlers = alloc(sizeof(struct registered_device) * handlers_cap); | ||
| assert(handlers, "Failed to allocate handlers vector"); | ||
| } | ||
|
|
||
| if (handlers_cap == handlers_len) { | ||
| handlers_cap *= 2; | ||
| struct registered_device *new_handlers = | ||
| realloc(handlers, sizeof(struct registered_device) * handlers_cap); | ||
| assert(new_handlers, "Failed to reallocate pci handlers vector"); | ||
| handlers = new_handlers; | ||
| } | ||
|
|
||
| handlers[handlers_len++] = | ||
| (struct registered_device){.vid = vid, .did = did, .callback = callback}; | ||
| } | ||
|
|
||
| void (*pci_get_handler(u16 vid, u16 did))(struct pci *this, | ||
| struct pci_regs *regs) { | ||
| for (usize i = 0; i < handlers_len; ++i) { | ||
| if (handlers[i].vid == vid && handlers[i].did == did) | ||
| return handlers[i].callback; | ||
| } | ||
| return nullptr; | ||
| } |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,196 @@ | ||
| /* | ||
| * SPDX-FileCopyrightText: ukoOS Contributors | ||
| * | ||
| * SPDX-License-Identifier: GPL-3.0-or-later | ||
| */ | ||
|
|
||
| #include <container.h> | ||
| #include <devicetree.h> | ||
| #include <endian.h> | ||
| #include <mm/paging.h> | ||
| #include <mm/virtual_alloc.h> | ||
| #include <physical.h> | ||
| #include <print.h> | ||
| #include <volatile.h> | ||
|
|
||
| #include <devices/pci.h> | ||
|
|
||
| struct pci_device { | ||
| struct device device; | ||
| struct pci pci; | ||
| void *reg_base; | ||
| struct vma_allocator *mmio_low_allocator; | ||
| struct vma_allocator *mmio_high_allocator; | ||
| }; | ||
|
|
||
| union pci_device_addr { | ||
| struct { | ||
| u32 offset : 8; | ||
| u32 func : 3; | ||
| u32 dev : 5; | ||
| u32 bus : 8; | ||
| u32 rsvd : 7; | ||
| u32 enable : 1; | ||
| }; | ||
| u32 bits; | ||
| }; | ||
|
|
||
| void register_device(struct pci *this, u16 vid, u16 did, | ||
| void (*callback)(struct pci *this, void *regs)); | ||
| struct vma *mmio_alloc(struct pci *this, usize len, bool want_low_addr); | ||
|
|
||
| static struct pci_ops pci_device_ops = {.mmio_alloc = mmio_alloc}; | ||
| static_assert(offsetof(struct pci_regs, memar) == 0x14); | ||
|
|
||
| struct vma *mmio_alloc(struct pci *this, usize num_pages, bool want_low_addr) { | ||
| struct pci_device *dev = container_of(this, struct pci_device, pci); | ||
| struct vma_allocator *allocator; | ||
|
|
||
| if (want_low_addr) { | ||
| allocator = dev->mmio_low_allocator; | ||
| } else { | ||
| allocator = dev->mmio_high_allocator; | ||
| } | ||
|
|
||
| return vma_alloc(allocator, num_pages); | ||
| } | ||
|
|
||
| void pci_enumerate(struct pci *this, void *reg_base) { | ||
|
|
||
| for (u32 bus = 0; bus < 256; ++bus) { | ||
| for (u32 dev = 0; dev < 32; ++dev) { | ||
| union pci_device_addr addr; | ||
| addr.offset = 0; | ||
| addr.func = 0; | ||
| addr.dev = dev & 31; | ||
| addr.bus = bus & 255; | ||
|
|
||
| struct pci_regs *device = (struct pci_regs *)(reg_base + addr.bits); | ||
|
|
||
| u16 did = READ_ONCE(&device->did); | ||
| u16 vid = READ_ONCE(&device->vid); | ||
|
|
||
| if (did == 0xffff && vid == 0xffff) | ||
| continue; | ||
|
|
||
| void (*callback)(struct pci *, struct pci_regs *) = | ||
| pci_get_handler(vid, did); | ||
|
|
||
| if (callback) { | ||
| callback(this, device); | ||
| } else { | ||
| print("Unbekannt pci Gerät: {u16:x} Anbieter: {u16:x}", did, vid); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| static struct device *pci_enumerate_dt(struct devicetree_node *node) { | ||
| struct pci_device *device = nullptr; | ||
| paddr reg_addr; | ||
| usize reg_size; | ||
| u32 address_cells, size_cells; | ||
| u32 parent_address_cells, parent_size_cells; | ||
|
|
||
| uaddr mmio_32bit_low, mmio_32bit_high; | ||
| uaddr mmio_64bit_low, mmio_64bit_high; | ||
|
|
||
| if (!devicetree_reg(node, 0, ®_addr, ®_size)) | ||
| goto fail; | ||
|
|
||
| if (reg_size < sizeof(struct pci_regs)) | ||
| goto fail; | ||
|
|
||
| device = alloc(sizeof(struct pci_device)); | ||
| if (!device) | ||
| goto fail; | ||
|
|
||
| if (!devicetree_address_size_cells(node, &address_cells, &size_cells)) | ||
| goto fail; | ||
|
|
||
| if (!devicetree_address_size_cells(node->parent, &parent_address_cells, | ||
| &parent_size_cells)) | ||
| goto fail; | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. assert size_cells, address_size, ... |
||
| devicetree_print(node->parent); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. remove |
||
|
|
||
| usize triplet_size = (address_cells + parent_address_cells + size_cells) * 4; | ||
| struct devicetree_prop *base = devicetree_prop(node, "ranges"); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. goto fail |
||
|
|
||
| /* TODO: when we allow adding ranges of memory to a VMA allocator, make this | ||
| * add each range as we iterate. Currently, this PCI device only has 1 of | ||
| * each, so it is not an issue. | ||
| */ | ||
| mmio_32bit_low = 0; | ||
| mmio_32bit_high = 0; | ||
| mmio_64bit_low = 0; | ||
| mmio_64bit_high = 0; | ||
|
|
||
| for (usize i = 0; i < base->value_len; i += triplet_size) { | ||
| union pci_bus_addr bus_addr; | ||
| u64 addr, size; | ||
|
|
||
| memcpy(&bus_addr.bits, &base->value[i], 4); | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. TODO: what to do with the rest of the address |
||
| memcpy(&addr, &base->value[i + address_cells * 4], | ||
| parent_address_cells * 4); | ||
| memcpy(&size, &base->value[i + (address_cells + parent_address_cells) * 4], | ||
| size_cells * 4); | ||
|
|
||
| addr = big_to_native(addr); | ||
| size = big_to_native(size); | ||
| bus_addr.bits = big_to_native(bus_addr.bits); | ||
|
|
||
| switch (bus_addr.space_code) { | ||
| case SPACE_CODE_MMIO_32: | ||
| mmio_32bit_low = addr; | ||
| mmio_32bit_high = addr + size; | ||
| break; | ||
| case SPACE_CODE_MMIO_64: | ||
| mmio_64bit_low = addr; | ||
| mmio_64bit_high = addr + size; | ||
| break; | ||
| default: | ||
| /* SPACE_CODE_IO and CONFIG ignored*/ | ||
| } | ||
| } | ||
|
|
||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. check if mmio_64/32bit_low/high are 0 |
||
| if (base) | ||
| print("{u64}", base->value_len); | ||
|
|
||
| *device = (struct pci_device){ | ||
| .device = DEVICE_INIT(device->device, "pci@{paddr}", reg_addr), | ||
| .pci = | ||
| { | ||
| .list = LIST_INIT(device->pci.list), | ||
| .ops = &pci_device_ops, | ||
| .device = &device->device, | ||
| }, | ||
| .reg_base = iomem_map(reg_addr, reg_size), | ||
| .mmio_low_allocator = vma_allocator_new(mmio_32bit_low, mmio_32bit_high), | ||
| .mmio_high_allocator = | ||
| vma_allocator_new(mmio_64bit_low, mmio_64bit_high)}; | ||
|
|
||
| if (!device->device.name || !device->reg_base) | ||
| goto fail; | ||
|
|
||
| if (!device->mmio_low_allocator || !device->mmio_high_allocator) | ||
| goto fail; | ||
|
|
||
| list_push(&pcis, &device->pci.list); | ||
|
|
||
| pci_enumerate(&device->pci, device->reg_base); | ||
|
|
||
| return &device->device; | ||
|
|
||
| fail: | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. clean up vma_allocator |
||
| if (device) { | ||
| free(device->device.name); | ||
| iomem_unmap(device->reg_base, reg_size); | ||
| } | ||
| free(device); | ||
| return nullptr; | ||
| } | ||
|
|
||
| DEFINE_INIT(INIT_REGISTER_DRIVERS) { | ||
| devicetree_register("pci-host-ecam-generic", pci_enumerate_dt); | ||
| } | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
are these physical addresses, pci addresses? what is the address space