forked from Bananymous/banan-os
				
			1000th COMMIT: Kernel: Add basic E1000 driver
This driver is only capable to read mac address and enable and read link status
This commit is contained in:
		
							parent
							
								
									5fae3cec2a
								
							
						
					
					
						commit
						14a608effd
					
				|  | @ -38,6 +38,7 @@ set(KERNEL_SOURCES | |||
| 	kernel/Memory/kmalloc.cpp | ||||
| 	kernel/Memory/PhysicalRange.cpp | ||||
| 	kernel/Memory/VirtualRange.cpp | ||||
| 	kernel/Networking/E1000.cpp | ||||
| 	kernel/OpenFileDescriptorSet.cpp | ||||
| 	kernel/Panic.cpp | ||||
| 	kernel/PCI.cpp | ||||
|  |  | |||
|  | @ -0,0 +1,58 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/UniqPtr.h> | ||||
| #include <kernel/Networking/NetworkDriver.h> | ||||
| #include <kernel/PCI.h> | ||||
| 
 | ||||
| #define E1000_NUM_RX_DESC 32 | ||||
| #define E1000_NUM_TX_DESC 8 | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	class E1000 final : public NetworkDriver | ||||
| 	{ | ||||
| 	public: | ||||
| 		static BAN::ErrorOr<BAN::UniqPtr<E1000>> create(const PCIDevice&); | ||||
| 		~E1000(); | ||||
| 
 | ||||
| 		virtual uint8_t* get_mac_address() override { return m_mac_address; } | ||||
| 		virtual BAN::ErrorOr<void> send_packet(const void* data, uint16_t len) override; | ||||
| 
 | ||||
| 		virtual bool link_up() override { return m_link_up; } | ||||
| 		virtual int link_speed() override; | ||||
| 
 | ||||
| 	private: | ||||
| 		E1000() = default; | ||||
| 		BAN::ErrorOr<void> initialize(const PCIDevice&); | ||||
| 
 | ||||
| 		static void interrupt_handler(); | ||||
| 
 | ||||
| 		void write32(uint16_t reg, uint32_t value); | ||||
| 		uint32_t read32(uint16_t reg); | ||||
| 
 | ||||
| 		void detect_eeprom(); | ||||
| 		uint32_t eeprom_read(uint8_t addr); | ||||
| 		BAN::ErrorOr<void> read_mac_address(); | ||||
| 
 | ||||
| 		void initialize_rx(); | ||||
| 		void initialize_tx(); | ||||
| 
 | ||||
| 		void enable_link(); | ||||
| 		void enable_interrupts(); | ||||
| 		 | ||||
| 		void handle_receive(); | ||||
| 
 | ||||
| 	private: | ||||
| 		PCIDevice::BarType		m_bar_type {}; | ||||
| 		uint64_t				m_bar_addr {}; | ||||
| 		bool					m_has_eerprom { false }; | ||||
| 		uint8_t					m_mac_address[6] {}; | ||||
| 		uint16_t				m_rx_current {}; | ||||
| 		uint16_t				m_tx_current {}; | ||||
| 		struct e1000_rx_desc*	m_rx_descs[E1000_NUM_RX_DESC] {}; | ||||
| 		struct e1000_tx_desc*	m_tx_descs[E1000_NUM_TX_DESC] {}; | ||||
| 		bool					m_link_up { false }; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -0,0 +1,20 @@ | |||
| #pragma once | ||||
| 
 | ||||
| #include <BAN/Errors.h> | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	class NetworkDriver | ||||
| 	{ | ||||
| 	public: | ||||
| 		virtual ~NetworkDriver() {} | ||||
| 
 | ||||
| 		virtual uint8_t* get_mac_address() = 0; | ||||
| 		virtual BAN::ErrorOr<void> send_packet(const void* data, uint16_t len) = 0; | ||||
| 
 | ||||
| 		virtual bool link_up() = 0; | ||||
| 		virtual int link_speed() = 0; | ||||
| 	}; | ||||
| 
 | ||||
| } | ||||
|  | @ -7,6 +7,14 @@ namespace Kernel | |||
| 
 | ||||
| 	class PCIDevice | ||||
| 	{ | ||||
| 	public: | ||||
| 		enum class BarType | ||||
| 		{ | ||||
| 			INVAL, | ||||
| 			MEM, | ||||
| 			IO, | ||||
| 		}; | ||||
| 
 | ||||
| 	public: | ||||
| 		PCIDevice(uint8_t, uint8_t, uint8_t); | ||||
| 
 | ||||
|  | @ -24,6 +32,9 @@ namespace Kernel | |||
| 		uint8_t subclass() const { return m_subclass; } | ||||
| 		uint8_t prog_if() const { return m_prog_if; } | ||||
| 
 | ||||
| 		BarType read_bar_type(uint8_t) const; | ||||
| 		uint64_t read_bar_address(uint8_t) const; | ||||
| 
 | ||||
| 		void enable_bus_mastering() const; | ||||
| 		void disable_bus_mastering() const; | ||||
| 
 | ||||
|  | @ -41,6 +52,8 @@ namespace Kernel | |||
| 		uint8_t m_class_code; | ||||
| 		uint8_t m_subclass; | ||||
| 		uint8_t m_prog_if; | ||||
| 
 | ||||
| 		uint8_t m_header_type; | ||||
| 	}; | ||||
| 
 | ||||
| 	class PCI | ||||
|  |  | |||
|  | @ -0,0 +1,381 @@ | |||
| #include <kernel/IDT.h> | ||||
| #include <kernel/InterruptController.h> | ||||
| #include <kernel/IO.h> | ||||
| #include <kernel/Memory/PageTable.h> | ||||
| #include <kernel/MMIO.h> | ||||
| #include <kernel/Networking/E1000.h> | ||||
| 
 | ||||
| #define E1000_GENERAL_MEM_SIZE		(128 * 1024) | ||||
| 
 | ||||
| #define E1000_REG_CTRL				0x0000 | ||||
| #define E1000_REG_STATUS			0x0008 | ||||
| #define E1000_REG_EEPROM			0x0014 | ||||
| #define E1000_REG_INT_CAUSE_READ	0x00C0 | ||||
| #define E1000_REG_INT_RATE			0x00C4 | ||||
| #define E1000_REG_INT_MASK_SET		0x00D0 | ||||
| #define E1000_REG_INT_MASK_CLEAR	0x00D8 | ||||
| #define E1000_REG_RCTRL				0x0100 | ||||
| #define E1000_REG_RXDESCLO			0x2800 | ||||
| #define E1000_REG_RXDESCHI			0x2804 | ||||
| #define E1000_REG_RXDESCLEN			0x2808 | ||||
| #define E1000_REG_RXDESCHEAD		0x2810 | ||||
| #define E1000_REG_RXDESCTAIL		0x2818 | ||||
| #define E1000_REG_TXDESCLO			0x3800 | ||||
| #define E1000_REG_TXDESCHI			0x3804 | ||||
| #define E1000_REG_TXDESCLEN			0x3808 | ||||
| #define E1000_REG_TXDESCHEAD		0x3810 | ||||
| #define E1000_REG_TXDESCTAIL		0x3818 | ||||
| #define E1000_REG_TCTRL				0x0400 | ||||
| #define E1000_REG_TIPG				0x0410 | ||||
| 
 | ||||
| #define E1000_STATUS_LINK_UP		0x02 | ||||
| #define E1000_STATUS_SPEED_MASK		0xC0 | ||||
| #define E1000_STATUS_SPEED_10MB		0x00 | ||||
| #define E1000_STATUS_SPEED_100MB	0x40 | ||||
| #define E1000_STATUS_SPEED_1000MB1	0x80 | ||||
| #define E1000_STATUS_SPEED_1000MB2	0xC0 | ||||
| 
 | ||||
| #define E1000_CTRL_SET_LINK_UP		0x40 | ||||
| 
 | ||||
| #define E1000_INT_TXDW		(1 << 0) | ||||
| #define E1000_INT_TXQE		(1 << 1) | ||||
| #define E1000_INT_LSC		(1 << 2) | ||||
| #define E1000_INT_RXSEQ		(1 << 3) | ||||
| #define E1000_INT_RXDMT0	(1 << 4) | ||||
| #define E1000_INT_RXO		(1 << 6) | ||||
| #define E1000_INT_RXT0		(1 << 7) | ||||
| #define E1000_INT_MDAC		(1 << 9) | ||||
| #define E1000_INT_RXCFG		(1 << 10) | ||||
| #define E1000_INT_PHYINT	(1 << 12) | ||||
| #define E1000_INT_TXD_LOW	(1 << 15) | ||||
| #define E1000_INT_SRPD		(1 << 16) | ||||
| 
 | ||||
| 
 | ||||
| #define E1000_TCTL_EN			(1 << 1) | ||||
| #define E1000_TCTL_PSP			(1 << 3) | ||||
| #define E1000_TCTL_CT_SHIFT		4 | ||||
| #define E1000_TCTL_COLD_SHIFT	12 | ||||
| #define E1000_TCTL_SWXOFF		(1 << 22) | ||||
| #define E1000_TCTL_RTLC			(1 << 24) | ||||
| 
 | ||||
| #define E1000_RCTL_EN				(1 << 1) | ||||
| #define E1000_RCTL_SBP				(1 << 2) | ||||
| #define E1000_RCTL_UPE				(1 << 3) | ||||
| #define E1000_RCTL_MPE				(1 << 4) | ||||
| #define E1000_RCTL_LPE				(1 << 5) | ||||
| #define E1000_RCTL_LBM_NONE			(0 << 6) | ||||
| #define E1000_RCTL_LBM_PHY			(3 << 6) | ||||
| #define E1000_RTCL_RDMTS_HALF		(0 << 8) | ||||
| #define E1000_RTCL_RDMTS_QUARTER	(1 << 8) | ||||
| #define E1000_RTCL_RDMTS_EIGHTH		(2 << 8) | ||||
| #define E1000_RCTL_MO_36			(0 << 12) | ||||
| #define E1000_RCTL_MO_35			(1 << 12) | ||||
| #define E1000_RCTL_MO_34			(2 << 12) | ||||
| #define E1000_RCTL_MO_32			(3 << 12) | ||||
| #define E1000_RCTL_BAM				(1 << 15) | ||||
| #define E1000_RCTL_VFE				(1 << 18) | ||||
| #define E1000_RCTL_CFIEN			(1 << 19) | ||||
| #define E1000_RCTL_CFI				(1 << 20) | ||||
| #define E1000_RCTL_DPF				(1 << 22) | ||||
| #define E1000_RCTL_PMCF				(1 << 23) | ||||
| #define E1000_RCTL_SECRC			(1 << 26) | ||||
| 
 | ||||
| #define E1000_RCTL_BSIZE_256		(3 << 16) | ||||
| #define E1000_RCTL_BSIZE_512		(2 << 16) | ||||
| #define E1000_RCTL_BSIZE_1024		(1 << 16) | ||||
| #define E1000_RCTL_BSIZE_2048		(0 << 16) | ||||
| #define E1000_RCTL_BSIZE_4096		((3 << 16) | (1 << 25)) | ||||
| #define E1000_RCTL_BSIZE_8192		((2 << 16) | (1 << 25)) | ||||
| #define E1000_RCTL_BSIZE_16384		((1 << 16) | (1 << 25)) | ||||
| 
 | ||||
| namespace Kernel | ||||
| { | ||||
| 
 | ||||
| 	struct e1000_rx_desc | ||||
| 	{ | ||||
| 		volatile uint64_t addr; | ||||
| 		volatile uint16_t length; | ||||
| 		volatile uint16_t checksum; | ||||
| 		volatile uint8_t status; | ||||
| 		volatile uint8_t errors; | ||||
| 		volatile uint16_t special; | ||||
| 	} __attribute__((packed)); | ||||
| 
 | ||||
| 	struct e1000_tx_desc | ||||
| 	{ | ||||
| 		volatile uint64_t addr; | ||||
| 		volatile uint16_t length; | ||||
| 		volatile uint8_t cso; | ||||
| 		volatile uint8_t cmd; | ||||
| 		volatile uint8_t status; | ||||
| 		volatile uint8_t css; | ||||
| 		volatile uint16_t special; | ||||
| 	} __attribute__((packed)); | ||||
| 
 | ||||
| 	BAN::ErrorOr<BAN::UniqPtr<E1000>> E1000::create(const PCIDevice& pci_device) | ||||
| 	{ | ||||
| 		E1000* e1000 = new E1000(); | ||||
| 		ASSERT(e1000); | ||||
| 		if (auto ret = e1000->initialize(pci_device); ret.is_error()) | ||||
| 		{ | ||||
| 			delete e1000; | ||||
| 			return ret.release_error(); | ||||
| 		} | ||||
| 		return BAN::UniqPtr<E1000>::adopt(e1000); | ||||
| 	} | ||||
| 
 | ||||
| 	E1000::~E1000() | ||||
| 	{ | ||||
| 		if (m_bar_type == PCIDevice::BarType::MEM && m_bar_addr) | ||||
| 			PageTable::kernel().unmap_range(m_bar_addr & PAGE_ADDR_MASK, E1000_GENERAL_MEM_SIZE); | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> E1000::initialize(const PCIDevice& pci_device) | ||||
| 	{ | ||||
| 		m_bar_type = pci_device.read_bar_type(0); | ||||
| 		if (m_bar_type == PCIDevice::BarType::INVAL) | ||||
| 		{ | ||||
| 			dwarnln("invalid bar0 type"); | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		if (m_bar_type == PCIDevice::BarType::MEM) | ||||
| 		{ | ||||
| 			uint64_t bar_addr = pci_device.read_bar_address(0); | ||||
| 
 | ||||
| 			vaddr_t page_vaddr = PageTable::kernel().reserve_free_contiguous_pages(E1000_GENERAL_MEM_SIZE / PAGE_SIZE, KERNEL_OFFSET); | ||||
| 			paddr_t page_paddr = bar_addr & PAGE_ADDR_MASK; | ||||
| 			PageTable::kernel().map_range_at(page_paddr, page_vaddr, E1000_GENERAL_MEM_SIZE, PageTable::Flags::CacheDisable | PageTable::Flags::ReadWrite | PageTable::Flags::Present); | ||||
| 
 | ||||
| 			m_bar_addr = page_vaddr + (bar_addr % PAGE_SIZE); | ||||
| 		} | ||||
| 		else if (m_bar_type == PCIDevice::BarType::IO) | ||||
| 		{ | ||||
| 			m_bar_addr = pci_device.read_bar_address(0); | ||||
| 		} | ||||
| 
 | ||||
| 		pci_device.enable_bus_mastering(); | ||||
| 
 | ||||
| 		detect_eeprom(); | ||||
| 
 | ||||
| 		TRY(read_mac_address()); | ||||
| 		 | ||||
| 		dprintln("E1000 at PCI {}:{}.{}", pci_device.bus(), pci_device.dev(), pci_device.func()); | ||||
| 
 | ||||
| 		dprintln("  MAC: {2H}:{2H}:{2H}:{2H}:{2H}:{2H}", | ||||
| 			m_mac_address[0], | ||||
| 			m_mac_address[1], | ||||
| 			m_mac_address[2], | ||||
| 			m_mac_address[3], | ||||
| 			m_mac_address[4], | ||||
| 			m_mac_address[5] | ||||
| 		); | ||||
| 
 | ||||
| 		initialize_rx(); | ||||
| 		initialize_tx(); | ||||
| 
 | ||||
| 		enable_link(); | ||||
| 		enable_interrupts(); | ||||
| 		 | ||||
| 		dprintln("  link up: {}", link_up()); | ||||
| 		if (link_up()) | ||||
| 			dprintln("  link speed: {} Mbps", link_speed()); | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	void E1000::write32(uint16_t reg, uint32_t value) | ||||
| 	{ | ||||
| 		switch (m_bar_type) | ||||
| 		{ | ||||
| 			case PCIDevice::BarType::MEM: | ||||
| 				MMIO::write32(m_bar_addr + reg, value); | ||||
| 				break; | ||||
| 			case PCIDevice::BarType::IO: | ||||
| 				IO::outl(m_bar_addr, reg); | ||||
| 				IO::outl(m_bar_addr + 4, value); | ||||
| 				break; | ||||
| 			default: | ||||
| 				ASSERT_NOT_REACHED(); | ||||
| 		} | ||||
| 	} | ||||
| 
 | ||||
| 	uint32_t E1000::read32(uint16_t reg) | ||||
| 	{ | ||||
| 		uint32_t result = 0; | ||||
| 		switch (m_bar_type) | ||||
| 		{ | ||||
| 			case PCIDevice::BarType::MEM: | ||||
| 				result = MMIO::read32(m_bar_addr + reg); | ||||
| 				break; | ||||
| 			case PCIDevice::BarType::IO: | ||||
| 				IO::outl(m_bar_addr, reg); | ||||
| 				result = IO::inl(m_bar_addr + 4); | ||||
| 				break; | ||||
| 			default: | ||||
| 				ASSERT_NOT_REACHED(); | ||||
| 		} | ||||
| 		return result; | ||||
| 	} | ||||
| 
 | ||||
| 	void E1000::detect_eeprom() | ||||
| 	{ | ||||
| 		m_has_eerprom = false; | ||||
| 		write32(E1000_REG_EEPROM, 0x01); | ||||
| 		for (int i = 0; i < 1000 && !m_has_eerprom; i++) | ||||
| 			if (read32(E1000_REG_EEPROM) & 0x10) | ||||
| 				m_has_eerprom = true; | ||||
| 	} | ||||
| 
 | ||||
| 	uint32_t E1000::eeprom_read(uint8_t address) | ||||
| 	{ | ||||
| 		uint32_t tmp = 0; | ||||
| 		if (m_has_eerprom) | ||||
| 		{ | ||||
| 			write32(E1000_REG_EEPROM, ((uint32_t)address << 8) | 1); | ||||
| 			while (!((tmp = read32(E1000_REG_EEPROM)) & (1 << 4))) | ||||
| 				continue; | ||||
| 		} | ||||
| 		else | ||||
| 		{ | ||||
| 			write32(E1000_REG_EEPROM, ((uint32_t)address << 2) | 1); | ||||
| 			while (!((tmp = read32(E1000_REG_EEPROM)) & (1 << 1))) | ||||
| 				continue; | ||||
| 		} | ||||
| 		return (tmp >> 16) & 0xFFFF; | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> E1000::read_mac_address() | ||||
| 	{ | ||||
| 		if (m_has_eerprom) | ||||
| 		{ | ||||
| 			uint32_t temp = eeprom_read(0); | ||||
| 			m_mac_address[0] = temp; | ||||
| 			m_mac_address[1] = temp >> 8; | ||||
| 			 | ||||
| 			temp = eeprom_read(1); | ||||
| 			m_mac_address[2] = temp; | ||||
| 			m_mac_address[3] = temp >> 8; | ||||
| 			 | ||||
| 			temp = eeprom_read(2); | ||||
| 			m_mac_address[4] = temp; | ||||
| 			m_mac_address[5] = temp >> 8; | ||||
| 
 | ||||
| 			return {}; | ||||
| 		} | ||||
| 
 | ||||
| 		if (read32(0x5400) == 0) | ||||
| 		{ | ||||
| 			dwarnln("no mac address"); | ||||
| 			return BAN::Error::from_errno(EINVAL); | ||||
| 		} | ||||
| 
 | ||||
| 		for (int i = 0; i < 6; i++) | ||||
| 			m_mac_address[i] = (uint8_t)read32(0x5400 + i * 8); | ||||
| 
 | ||||
| 		return {}; | ||||
| 	} | ||||
| 
 | ||||
| 	void E1000::initialize_rx() | ||||
| 	{ | ||||
| 		uint8_t* ptr = (uint8_t*)kmalloc(sizeof(e1000_rx_desc) * E1000_NUM_RX_DESC + 16, 16, true); | ||||
| 		ASSERT(ptr); | ||||
| 
 | ||||
| 		e1000_rx_desc* descs = (e1000_rx_desc*)ptr; | ||||
| 		for (int i = 0; i < E1000_NUM_RX_DESC; i++) | ||||
| 		{ | ||||
| 			// FIXME
 | ||||
| 			m_rx_descs[i] = &descs[i]; | ||||
| 			m_rx_descs[i]->addr = 0; | ||||
| 			m_rx_descs[i]->status = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		write32(E1000_REG_RXDESCLO, (uintptr_t)ptr >> 32); | ||||
| 		write32(E1000_REG_RXDESCHI, (uintptr_t)ptr & 0xFFFFFFFF); | ||||
| 		write32(E1000_REG_RXDESCLEN, E1000_NUM_RX_DESC * sizeof(e1000_rx_desc)); | ||||
| 		write32(E1000_REG_RXDESCHEAD, 0); | ||||
| 		write32(E1000_REG_RXDESCTAIL, E1000_NUM_RX_DESC - 1); | ||||
| 
 | ||||
| 		m_rx_current = 0; | ||||
| 		 | ||||
| 		uint32_t rctrl = 0; | ||||
| 		rctrl |= E1000_RCTL_EN; | ||||
| 		rctrl |= E1000_RCTL_SBP; | ||||
| 		rctrl |= E1000_RCTL_UPE; | ||||
| 		rctrl |= E1000_RCTL_MPE; | ||||
| 		rctrl |= E1000_RCTL_LBM_NONE; | ||||
| 		rctrl |= E1000_RTCL_RDMTS_HALF; | ||||
| 		rctrl |= E1000_RCTL_BAM; | ||||
| 		rctrl |= E1000_RCTL_SECRC; | ||||
| 		rctrl |= E1000_RCTL_BSIZE_8192; | ||||
| 
 | ||||
|    		write32(E1000_REG_RCTRL, rctrl); | ||||
| 	} | ||||
| 
 | ||||
| 	void E1000::initialize_tx() | ||||
| 	{ | ||||
| 		auto* ptr = (uint8_t*)kmalloc(sizeof(e1000_tx_desc) * E1000_NUM_TX_DESC + 16, 16, true); | ||||
| 		ASSERT(ptr); | ||||
| 
 | ||||
| 		auto* descs = (e1000_tx_desc*)ptr; | ||||
| 		for(int i = 0; i < E1000_NUM_TX_DESC; i++) | ||||
| 		{ | ||||
| 			// FIXME
 | ||||
| 			m_tx_descs[i] = &descs[i]; | ||||
| 			m_tx_descs[i]->addr = 0; | ||||
| 			m_tx_descs[i]->cmd = 0; | ||||
| 		} | ||||
| 
 | ||||
| 		write32(E1000_REG_TXDESCHI, (uintptr_t)ptr >> 32); | ||||
| 		write32(E1000_REG_TXDESCLO, (uintptr_t)ptr & 0xFFFFFFFF); | ||||
| 		write32(E1000_REG_TXDESCLEN, E1000_NUM_TX_DESC * sizeof(e1000_tx_desc)); | ||||
| 		write32(E1000_REG_TXDESCHEAD, 0); | ||||
| 		write32(E1000_REG_TXDESCTAIL, 0); | ||||
| 
 | ||||
| 		m_tx_current = 0; | ||||
| 
 | ||||
| 		write32(E1000_REG_TCTRL, read32(E1000_REG_TCTRL) | E1000_TCTL_EN | E1000_TCTL_PSP); | ||||
| 		write32(E1000_REG_TIPG, 0x0060200A); | ||||
| 	} | ||||
| 
 | ||||
| 	void E1000::enable_link() | ||||
| 	{ | ||||
| 		write32(E1000_REG_CTRL, read32(E1000_REG_CTRL) | E1000_CTRL_SET_LINK_UP); | ||||
| 		m_link_up = !!(read32(E1000_REG_STATUS) & E1000_STATUS_LINK_UP); | ||||
| 	} | ||||
| 
 | ||||
| 	int E1000::link_speed() | ||||
| 	{ | ||||
| 		if (!link_up()) | ||||
| 			return 0; | ||||
| 		uint32_t speed = read32(E1000_REG_STATUS) & E1000_STATUS_SPEED_MASK; | ||||
| 		if (speed == E1000_STATUS_SPEED_10MB) | ||||
| 			return 10; | ||||
| 		if (speed == E1000_STATUS_SPEED_100MB) | ||||
| 			return 100; | ||||
| 		if (speed == E1000_STATUS_SPEED_1000MB1) | ||||
| 			return 1000; | ||||
| 		if (speed == E1000_STATUS_SPEED_1000MB2) | ||||
| 			return 1000; | ||||
| 		return 0; | ||||
| 	} | ||||
| 
 | ||||
| 	void E1000::enable_interrupts() | ||||
| 	{ | ||||
| 		write32(E1000_REG_INT_RATE, 6000); | ||||
| 		write32(E1000_REG_INT_MASK_SET, E1000_INT_LSC | E1000_INT_RXT0 | E1000_INT_RXO); | ||||
| 		read32(E1000_REG_INT_CAUSE_READ); | ||||
| 
 | ||||
| 		// FIXME: implement PCI interrupt allocation
 | ||||
| 		//IDT::register_irq_handler(irq, E1000::interrupt_handler);
 | ||||
| 		//InterruptController::enable_irq(irq);
 | ||||
| 	} | ||||
| 
 | ||||
| 	BAN::ErrorOr<void> E1000::send_packet(const void* data, uint16_t len) | ||||
| 	{ | ||||
| 		(void)data; | ||||
| 		(void)len; | ||||
| 		return BAN::Error::from_errno(ENOTSUP); | ||||
| 	} | ||||
| 
 | ||||
| } | ||||
|  | @ -1,4 +1,5 @@ | |||
| #include <kernel/IO.h> | ||||
| #include <kernel/Networking/E1000.h> | ||||
| #include <kernel/PCI.h> | ||||
| #include <kernel/Storage/ATAController.h> | ||||
| 
 | ||||
|  | @ -105,7 +106,7 @@ namespace Kernel | |||
| 					{ | ||||
| 						case 0x01: | ||||
| 							if (auto res = ATAController::create(pci_device); res.is_error()) | ||||
| 								dprintln("{}", res.error()); | ||||
| 								dprintln("ATA: {}", res.error()); | ||||
| 							break; | ||||
| 						default: | ||||
| 							dprintln("unsupported storage device (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if()); | ||||
|  | @ -113,6 +114,20 @@ namespace Kernel | |||
| 					} | ||||
| 					break; | ||||
| 				} | ||||
| 				case 0x02: | ||||
| 				{ | ||||
| 					switch (pci_device.subclass()) | ||||
| 					{ | ||||
| 						case 0x00: | ||||
| 							if (auto res = E1000::create(pci_device); res.is_error()) | ||||
| 								dprintln("E1000: {}", res.error()); | ||||
| 							break; | ||||
| 						default: | ||||
| 							dprintln("unsupported ethernet device (pci {2H}.{2H}.{2H})", pci_device.class_code(), pci_device.subclass(), pci_device.prog_if()); | ||||
| 							break; | ||||
| 					} | ||||
| 					break; | ||||
| 				} | ||||
| 				default: | ||||
| 					break; | ||||
| 			} | ||||
|  | @ -126,6 +141,7 @@ namespace Kernel | |||
| 		m_class_code  = (uint8_t)(type >> 8); | ||||
| 		m_subclass    = (uint8_t)(type); | ||||
| 		m_prog_if     = read_byte(0x09); | ||||
| 		m_header_type = read_byte(0x0E); | ||||
| 	} | ||||
| 
 | ||||
| 	uint32_t PCIDevice::read_dword(uint8_t offset) const | ||||
|  | @ -153,6 +169,33 @@ namespace Kernel | |||
| 		write_config_dword(m_bus, m_dev, m_func, offset, value); | ||||
| 	} | ||||
| 
 | ||||
| 	PCIDevice::BarType PCIDevice::read_bar_type(uint8_t bar) const | ||||
| 	{ | ||||
| 		ASSERT(m_header_type == 0x00); | ||||
| 		ASSERT(bar <= 5); | ||||
| 
 | ||||
| 		uint32_t type = read_dword(0x10 + bar * 4) & 0b111; | ||||
| 		if (type & 1) | ||||
| 			return BarType::IO; | ||||
| 		type >>= 1; | ||||
| 		if (type == 0x0 || type == 0x2) | ||||
| 			return BarType::MEM; | ||||
| 		return BarType::INVAL; | ||||
| 	} | ||||
| 
 | ||||
| 	uint64_t PCIDevice::read_bar_address(uint8_t bar) const | ||||
| 	{ | ||||
| 		ASSERT(m_header_type == 0x00); | ||||
| 		ASSERT(bar <= 5); | ||||
| 
 | ||||
| 		uint64_t address = read_dword(0x10 + bar * 4); | ||||
| 		if (address & 1) | ||||
| 			return address & 0xFFFFFFFC; | ||||
| 		if ((address & 0b110) == 0b100) | ||||
| 			address |= (uint64_t)read_dword(0x10 + bar * 4 + 4) << 32; | ||||
| 		return address & 0xFFFFFFFFFFFFFFF0; | ||||
| 	} | ||||
| 
 | ||||
| 	void PCIDevice::enable_bus_mastering() const | ||||
| 	{ | ||||
| 		write_dword(0x04, read_dword(0x04) | 1u << 2); | ||||
|  |  | |||
		Loading…
	
		Reference in New Issue