mirror of
https://github.com/DragonOS-Community/DragonOS.git
synced 2025-06-20 01:46:31 +00:00
Patch ahci (#348)
* Modify the ahci module and delete the useless c code 修改ahci使其不再依赖旧的pci函数 删除旧的pci、msi函数代码
This commit is contained in:
@ -1,28 +0,0 @@
|
||||
#include "ia64_msi.h"
|
||||
|
||||
/**
|
||||
* @brief 生成架构相关的msi的message address
|
||||
*
|
||||
*/
|
||||
#define ia64_pci_get_arch_msi_message_address(processor) ((0xfee00000UL | (processor << 12)))
|
||||
|
||||
/**
|
||||
* @brief 生成架构相关的message data
|
||||
*
|
||||
*/
|
||||
#define ia64_pci_get_arch_msi_message_data(vector, processor, edge_trigger, assert) ((uint32_t)((vector & 0xff) | (edge_trigger == 1 ? 0 : (1 << 15)) | ((assert == 0) ? 0 : (1 << 14))))
|
||||
|
||||
/**
|
||||
* @brief 生成msi消息
|
||||
*
|
||||
* @param msi_desc msi描述符
|
||||
* @return struct msi_msg_t* msi消息指针(在描述符内)
|
||||
*/
|
||||
struct msi_msg_t *msi_arch_get_msg(struct msi_desc_t *msi_desc)
|
||||
{
|
||||
msi_desc->msg.address_hi = 0;
|
||||
msi_desc->msg.address_lo = ia64_pci_get_arch_msi_message_address(msi_desc->processor);
|
||||
msi_desc->msg.data = ia64_pci_get_arch_msi_message_data(msi_desc->irq_num, msi_desc->processor, msi_desc->edge_trigger, msi_desc->assert);
|
||||
msi_desc->msg.vector_control = 0;
|
||||
return &(msi_desc->msg);
|
||||
}
|
@ -1,11 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <driver/pci/msi.h>
|
||||
|
||||
/**
|
||||
* @brief 生成msi消息
|
||||
*
|
||||
* @param msi_desc msi描述符
|
||||
* @return struct msi_msg_t* msi消息指针(在描述符内)
|
||||
*/
|
||||
struct msi_msg_t *msi_arch_get_msg(struct msi_desc_t *msi_desc);
|
@ -1,17 +1,17 @@
|
||||
#pragma once
|
||||
#include <common/glib.h>
|
||||
#include<process/ptrace.h>
|
||||
#include <process/ptrace.h>
|
||||
|
||||
// 使用弱引用属性导出kallsyms中的符号表。
|
||||
// 采用weak属性是由于第一次编译时,kallsyms还未链接进来,若不使用weak属性则会报错
|
||||
extern const uint64_t kallsyms_address[] __attribute__((weak));
|
||||
extern const uint64_t kallsyms_num __attribute__((weak));
|
||||
extern const uint64_t kallsyms_names_index[] __attribute__((weak));
|
||||
extern const char* kallsyms_names __attribute__((weak));
|
||||
extern const char *kallsyms_names __attribute__((weak));
|
||||
|
||||
/**
|
||||
* @brief 追溯内核栈调用情况
|
||||
*
|
||||
*
|
||||
* @param regs 内核栈结构体
|
||||
*/
|
||||
void traceback(struct pt_regs * regs);
|
||||
void traceback(struct pt_regs *regs);
|
@ -1,10 +1,7 @@
|
||||
|
||||
all: ata.o ahci.o
|
||||
all: ata.o
|
||||
|
||||
CFLAGS += -I .
|
||||
|
||||
ata.o: ata.c
|
||||
$(CC) $(CFLAGS) -c ata.c -o ata.o
|
||||
|
||||
ahci.o: ahci/ahci.c
|
||||
$(CC) $(CFLAGS) -c ahci/ahci.c -o ahci/ahci.o
|
||||
$(CC) $(CFLAGS) -c ata.c -o ata.o
|
@ -1,32 +0,0 @@
|
||||
#include "ahci.h"
|
||||
#include <common/kprint.h>
|
||||
#include <mm/slab.h>
|
||||
#include <common/string.h>
|
||||
#include <common/block.h>
|
||||
#include <debug/bug.h>
|
||||
#include <common/kthread.h>
|
||||
|
||||
/// @brief 保留了对 pci设备获取 和 mm内存映射 的依赖
|
||||
void ahci_cpp_init(uint32_t *count_ahci_devices, struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES], struct pci_device_structure_general_device_t *gen_devs[MAX_AHCI_DEVICES])
|
||||
{
|
||||
kinfo("Initializing AHCI...");
|
||||
|
||||
pci_get_device_structure(0x1, 0x6, ahci_devs, count_ahci_devices);
|
||||
|
||||
if (*count_ahci_devices == 0)
|
||||
{
|
||||
kwarn("There is no AHCI device found on this computer!");
|
||||
return;
|
||||
}
|
||||
|
||||
for (int i = 0; i < *count_ahci_devices; i++)
|
||||
{
|
||||
gen_devs[i] = ((struct pci_device_structure_general_device_t *)(ahci_devs[i]));
|
||||
}
|
||||
|
||||
// 映射ABAR
|
||||
uint32_t bar5 = gen_devs[0]->BAR5;
|
||||
rs_map_phys(AHCI_MAPPING_BASE, (ul)(bar5)&PAGE_2M_MASK, PAGE_2M_SIZE, PAGE_KERNEL_PAGE);
|
||||
|
||||
kinfo("ABAR mapped!");
|
||||
}
|
@ -1,364 +1,5 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/blk_types.h>
|
||||
#include <driver/pci/pci.h>
|
||||
#include <mm/mm.h>
|
||||
|
||||
/**
|
||||
* @todo 加入io调度器(当操作系统实现了多进程之后要加入这个)
|
||||
*
|
||||
*/
|
||||
#define AHCI_MAPPING_BASE SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + AHCI_MAPPING_OFFSET
|
||||
|
||||
#define MAX_AHCI_DEVICES 100
|
||||
|
||||
#define HBA_PxCMD_ST 0x0001
|
||||
#define HBA_PxCMD_FRE 0x0010
|
||||
#define HBA_PxCMD_FR 0x4000
|
||||
#define HBA_PxCMD_CR 0x8000
|
||||
|
||||
#define AHCI_DEV_BUSY 0x80
|
||||
#define AHCI_DEV_DRQ 0x08
|
||||
|
||||
#define AHCI_CMD_READ_DMA_EXT 0x25
|
||||
#define AHCI_CMD_WRITE_DMA_EXT 0x30
|
||||
|
||||
#define HBA_PxIS_TFES (1 << 30) /* TFES - Task File Error Status */
|
||||
|
||||
#define AHCI_SUCCESS 0 // 请求成功
|
||||
#define E_NOEMPTYSLOT 1 // 没有空闲的slot
|
||||
#define E_PORT_HUNG 2 // 端口被挂起
|
||||
#define E_TASK_FILE_ERROR 3 // 任务文件错误
|
||||
#define E_UNSUPPORTED_CMD 4 // 不支持的命令
|
||||
|
||||
extern struct block_device_operation ahci_operation;
|
||||
|
||||
/**
|
||||
* @brief 在SATA3.0规范中定义的Frame Information Structure类型
|
||||
*
|
||||
*/
|
||||
typedef enum
|
||||
{
|
||||
FIS_TYPE_REG_H2D = 0x27, // Register FIS - host to device
|
||||
FIS_TYPE_REG_D2H = 0x34, // Register FIS - device to host
|
||||
FIS_TYPE_DMA_ACT = 0x39, // DMA activate FIS - device to host
|
||||
FIS_TYPE_DMA_SETUP = 0x41, // DMA setup FIS - bidirectional
|
||||
FIS_TYPE_DATA = 0x46, // Data FIS - bidirectional
|
||||
FIS_TYPE_BIST = 0x58, // BIST activate FIS - bidirectional
|
||||
FIS_TYPE_PIO_SETUP = 0x5F, // PIO setup FIS - device to host
|
||||
FIS_TYPE_DEV_BITS = 0xA1, // Set device bits FIS - device to host
|
||||
} FIS_TYPE;
|
||||
|
||||
/**
|
||||
* @brief FIS_REG_H2D 被用于从主机向设备发送控制命令
|
||||
* 注意:reserved bit应当被清零
|
||||
*/
|
||||
typedef struct tagFIS_REG_H2D
|
||||
{
|
||||
// DWORD 0
|
||||
uint8_t fis_type; // FIS_TYPE_REG_H2D
|
||||
|
||||
uint8_t pmport : 4; // Port multiplier
|
||||
uint8_t rsv0 : 3; // Reserved
|
||||
uint8_t c : 1; // 1: Command, 0: Control
|
||||
|
||||
uint8_t command; // Command register
|
||||
uint8_t featurel; // Feature register, 7:0
|
||||
|
||||
// DWORD 1
|
||||
uint8_t lba0; // LBA low register, 7:0
|
||||
uint8_t lba1; // LBA mid register, 15:8
|
||||
uint8_t lba2; // LBA high register, 23:16
|
||||
uint8_t device; // Device register
|
||||
|
||||
// DWORD 2
|
||||
uint8_t lba3; // LBA register, 31:24
|
||||
uint8_t lba4; // LBA register, 39:32
|
||||
uint8_t lba5; // LBA register, 47:40
|
||||
uint8_t featureh; // Feature register, 15:8
|
||||
|
||||
// DWORD 3
|
||||
uint8_t countl; // Count register, 7:0
|
||||
uint8_t counth; // Count register, 15:8
|
||||
uint8_t icc; // Isochronous command completion
|
||||
uint8_t control; // Control register
|
||||
|
||||
// DWORD 4
|
||||
uint8_t rsv1[4]; // Reserved
|
||||
} FIS_REG_H2D;
|
||||
|
||||
// A device to host register FIS is used by the device to notify the host that some ATA register has changed.
|
||||
// It contains the updated task files such as status, error and other registers.
|
||||
typedef struct tagFIS_REG_D2H
|
||||
{
|
||||
// DWORD 0
|
||||
uint8_t fis_type; // FIS_TYPE_REG_D2H
|
||||
|
||||
uint8_t pmport : 4; // Port multiplier
|
||||
uint8_t rsv0 : 2; // Reserved
|
||||
uint8_t i : 1; // Interrupt bit
|
||||
uint8_t rsv1 : 1; // Reserved
|
||||
|
||||
uint8_t status; // Status register
|
||||
uint8_t error; // Error register
|
||||
|
||||
// DWORD 1
|
||||
uint8_t lba0; // LBA low register, 7:0
|
||||
uint8_t lba1; // LBA mid register, 15:8
|
||||
uint8_t lba2; // LBA high register, 23:16
|
||||
uint8_t device; // Device register
|
||||
|
||||
// DWORD 2
|
||||
uint8_t lba3; // LBA register, 31:24
|
||||
uint8_t lba4; // LBA register, 39:32
|
||||
uint8_t lba5; // LBA register, 47:40
|
||||
uint8_t rsv2; // Reserved
|
||||
|
||||
// DWORD 3
|
||||
uint8_t countl; // Count register, 7:0
|
||||
uint8_t counth; // Count register, 15:8
|
||||
uint8_t rsv3[2]; // Reserved
|
||||
|
||||
// DWORD 4
|
||||
uint8_t rsv4[4]; // Reserved
|
||||
} FIS_REG_D2H;
|
||||
|
||||
// This FIS is used by the host or device to send data payload. The data size can be varied.
|
||||
typedef struct tagFIS_DATA
|
||||
{
|
||||
// DWORD 0
|
||||
uint8_t fis_type; // FIS_TYPE_DATA
|
||||
|
||||
uint8_t pmport : 4; // Port multiplier
|
||||
uint8_t rsv0 : 4; // Reserved
|
||||
|
||||
uint8_t rsv1[2]; // Reserved
|
||||
|
||||
// DWORD 1 ~ N
|
||||
uint32_t data[1]; // Payload
|
||||
} FIS_DATA;
|
||||
|
||||
// This FIS is used by the device to tell the host that it’s about to send or ready to receive a PIO data payload.
|
||||
typedef struct tagFIS_PIO_SETUP
|
||||
{
|
||||
// DWORD 0
|
||||
uint8_t fis_type; // FIS_TYPE_PIO_SETUP
|
||||
|
||||
uint8_t pmport : 4; // Port multiplier
|
||||
uint8_t rsv0 : 1; // Reserved
|
||||
uint8_t d : 1; // Data transfer direction, 1 - device to host
|
||||
uint8_t i : 1; // Interrupt bit
|
||||
uint8_t rsv1 : 1;
|
||||
|
||||
uint8_t status; // Status register
|
||||
uint8_t error; // Error register
|
||||
|
||||
// DWORD 1
|
||||
uint8_t lba0; // LBA low register, 7:0
|
||||
uint8_t lba1; // LBA mid register, 15:8
|
||||
uint8_t lba2; // LBA high register, 23:16
|
||||
uint8_t device; // Device register
|
||||
|
||||
// DWORD 2
|
||||
uint8_t lba3; // LBA register, 31:24
|
||||
uint8_t lba4; // LBA register, 39:32
|
||||
uint8_t lba5; // LBA register, 47:40
|
||||
uint8_t rsv2; // Reserved
|
||||
|
||||
// DWORD 3
|
||||
uint8_t countl; // Count register, 7:0
|
||||
uint8_t counth; // Count register, 15:8
|
||||
uint8_t rsv3; // Reserved
|
||||
uint8_t e_status; // New value of status register
|
||||
|
||||
// DWORD 4
|
||||
uint16_t tc; // Transfer count
|
||||
uint8_t rsv4[2]; // Reserved
|
||||
} FIS_PIO_SETUP;
|
||||
|
||||
typedef struct tagFIS_DMA_SETUP
|
||||
{
|
||||
// DWORD 0
|
||||
uint8_t fis_type; // FIS_TYPE_DMA_SETUP
|
||||
|
||||
uint8_t pmport : 4; // Port multiplier
|
||||
uint8_t rsv0 : 1; // Reserved
|
||||
uint8_t d : 1; // Data transfer direction, 1 - device to host
|
||||
uint8_t i : 1; // Interrupt bit
|
||||
uint8_t a : 1; // Auto-activate. Specifies if DMA Activate FIS is needed
|
||||
|
||||
uint8_t rsved[2]; // Reserved
|
||||
|
||||
// DWORD 1&2
|
||||
|
||||
uint64_t DMAbufferID; // DMA Buffer Identifier. Used to Identify DMA buffer in host memory.
|
||||
// SATA Spec says host specific and not in Spec. Trying AHCI spec might work.
|
||||
|
||||
// DWORD 3
|
||||
uint32_t rsvd; // More reserved
|
||||
|
||||
// DWORD 4
|
||||
uint32_t DMAbufOffset; // Byte offset into buffer. First 2 bits must be 0
|
||||
|
||||
// DWORD 5
|
||||
uint32_t TransferCount; // Number of bytes to transfer. Bit 0 must be 0
|
||||
|
||||
// DWORD 6
|
||||
uint32_t resvd; // Reserved
|
||||
|
||||
} FIS_DMA_SETUP;
|
||||
|
||||
typedef volatile struct tagHBA_PORT
|
||||
{
|
||||
uint64_t clb; // 0x00, command list base address, 1K-byte aligned
|
||||
uint64_t fb; // 0x08, FIS base address, 256-byte aligned
|
||||
uint32_t is; // 0x10, interrupt status
|
||||
uint32_t ie; // 0x14, interrupt enable
|
||||
uint32_t cmd; // 0x18, command and status
|
||||
uint32_t rsv0; // 0x1C, Reserved
|
||||
uint32_t tfd; // 0x20, task file data
|
||||
uint32_t sig; // 0x24, signature
|
||||
uint32_t ssts; // 0x28, SATA status (SCR0:SStatus)
|
||||
uint32_t sctl; // 0x2C, SATA control (SCR2:SControl)
|
||||
uint32_t serr; // 0x30, SATA error (SCR1:SError)
|
||||
uint32_t sact; // 0x34, SATA active (SCR3:SActive)
|
||||
uint32_t ci; // 0x38, command issue
|
||||
uint32_t sntf; // 0x3C, SATA notification (SCR4:SNotification)
|
||||
uint32_t fbs; // 0x40, FIS-based switch control
|
||||
uint32_t rsv1[11]; // 0x44 ~ 0x6F, Reserved
|
||||
uint32_t vendor[4]; // 0x70 ~ 0x7F, vendor specific
|
||||
} HBA_PORT;
|
||||
typedef volatile struct tagHBA_MEM
|
||||
{
|
||||
// 0x00 - 0x2B, Generic Host Control
|
||||
uint32_t cap; // 0x00, Host capability
|
||||
uint32_t ghc; // 0x04, Global host control
|
||||
uint32_t is; // 0x08, Interrupt status
|
||||
uint32_t pi; // 0x0C, Port implemented
|
||||
uint32_t vs; // 0x10, Version
|
||||
uint32_t ccc_ctl; // 0x14, Command completion coalescing control
|
||||
uint32_t ccc_pts; // 0x18, Command completion coalescing ports
|
||||
uint32_t em_loc; // 0x1C, Enclosure management location
|
||||
uint32_t em_ctl; // 0x20, Enclosure management control
|
||||
uint32_t cap2; // 0x24, Host capabilities extended
|
||||
uint32_t bohc; // 0x28, BIOS/OS handoff control and status
|
||||
|
||||
// 0x2C - 0x9F, Reserved
|
||||
uint8_t rsv[0xA0 - 0x2C];
|
||||
|
||||
// 0xA0 - 0xFF, Vendor specific registers
|
||||
uint8_t vendor[0x100 - 0xA0];
|
||||
|
||||
// 0x100 - 0x10FF, Port control registers
|
||||
HBA_PORT ports[32]; // 1 ~ 32
|
||||
} HBA_MEM;
|
||||
|
||||
// There are four kinds of FIS which may be sent to the host by the device as indicated in the following structure declaration.
|
||||
//
|
||||
typedef volatile struct tagHBA_FIS
|
||||
{
|
||||
// 0x00
|
||||
FIS_DMA_SETUP dsfis; // DMA Setup FIS
|
||||
uint8_t pad0[4];
|
||||
|
||||
// 0x20
|
||||
FIS_PIO_SETUP psfis; // PIO Setup FIS
|
||||
uint8_t pad1[12];
|
||||
|
||||
// 0x40
|
||||
FIS_REG_D2H rfis; // Register – Device to Host FIS
|
||||
uint8_t pad2[4];
|
||||
|
||||
// 0x58
|
||||
// FIS_DEV_BITS sdbfis; // Set Device Bit FIS
|
||||
|
||||
// 0x60
|
||||
uint8_t ufis[64];
|
||||
|
||||
// 0xA0
|
||||
uint8_t rsv[0x100 - 0xA0];
|
||||
} HBA_FIS;
|
||||
|
||||
typedef struct tagHBA_CMD_HEADER
|
||||
{
|
||||
// DW0
|
||||
uint8_t cfl : 5; // Command FIS length in DWORDS, 2 ~ 16
|
||||
uint8_t a : 1; // ATAPI
|
||||
uint8_t w : 1; // Write, 1: H2D, 0: D2H
|
||||
uint8_t p : 1; // Prefetchable
|
||||
|
||||
uint8_t r : 1; // Reset
|
||||
uint8_t b : 1; // BIST
|
||||
uint8_t c : 1; // Clear busy upon R_OK
|
||||
uint8_t rsv0 : 1; // Reserved
|
||||
uint8_t pmp : 4; // Port multiplier port
|
||||
|
||||
uint16_t prdtl; // Physical region descriptor table length in entries
|
||||
|
||||
// DW1
|
||||
volatile uint32_t prdbc; // Physical region descriptor byte count transferred
|
||||
|
||||
// DW2, 3
|
||||
uint64_t ctba; // Command table descriptor base address
|
||||
|
||||
// DW4 - 7
|
||||
uint32_t rsv1[4]; // Reserved
|
||||
} HBA_CMD_HEADER;
|
||||
|
||||
typedef struct tagHBA_PRDT_ENTRY
|
||||
{
|
||||
uint64_t dba; // Data base address
|
||||
uint32_t rsv0; // Reserved
|
||||
|
||||
// DW3
|
||||
uint32_t dbc : 22; // Byte count, 4M max
|
||||
uint32_t rsv1 : 9; // Reserved
|
||||
uint32_t i : 1; // Interrupt on completion
|
||||
} HBA_PRDT_ENTRY;
|
||||
|
||||
typedef struct tagHBA_CMD_TBL
|
||||
{
|
||||
// 0x00
|
||||
uint8_t cfis[64]; // Command FIS
|
||||
|
||||
// 0x40
|
||||
uint8_t acmd[16]; // ATAPI command, 12 or 16 bytes
|
||||
|
||||
// 0x50
|
||||
uint8_t rsv[48]; // Reserved
|
||||
|
||||
// 0x80
|
||||
HBA_PRDT_ENTRY prdt_entry[1]; // Physical region descriptor table entries, 0 ~ 65535
|
||||
} HBA_CMD_TBL;
|
||||
|
||||
struct ahci_device_t
|
||||
{
|
||||
uint32_t type; // 设备类型
|
||||
struct pci_device_structure_header_t *dev_struct;
|
||||
HBA_MEM *hba_mem;
|
||||
} ahci_devices[MAX_AHCI_DEVICES];
|
||||
|
||||
#define SATA_SIG_ATA 0x00000101 // SATA drive
|
||||
#define SATA_SIG_ATAPI 0xEB140101 // SATAPI drive
|
||||
#define SATA_SIG_SEMB 0xC33C0101 // Enclosure management bridge
|
||||
#define SATA_SIG_PM 0x96690101 // Port multiplier
|
||||
|
||||
#define AHCI_DEV_NULL 0
|
||||
#define AHCI_DEV_SATA 1
|
||||
#define AHCI_DEV_SEMB 2
|
||||
#define AHCI_DEV_PM 3
|
||||
#define AHCI_DEV_SATAPI 4
|
||||
|
||||
#define HBA_PORT_IPM_ACTIVE 1
|
||||
#define HBA_PORT_DET_PRESENT 3
|
||||
|
||||
struct ahci_request_packet_t
|
||||
{
|
||||
struct block_device_request_packet blk_pak; // 块设备请求包
|
||||
uint8_t ahci_ctrl_num; // ahci控制器号, 默认应为0
|
||||
uint8_t port_num; // ahci的设备端口号
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 初始化ahci模块
|
||||
*
|
||||
|
@ -1,19 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/kprint.h>
|
||||
#include <mm/slab.h>
|
||||
#include <syscall/syscall.h>
|
||||
#include <syscall/syscall_num.h>
|
||||
#include <sched/sched.h>
|
||||
#include <common/string.h>
|
||||
#include <common/block.h>
|
||||
#include <debug/bug.h>
|
||||
#include <driver/pci/pci.h>
|
||||
#include <mm/mm.h>
|
||||
|
||||
// 计算HBA_MEM的虚拟内存地址
|
||||
#define MAX_AHCI_DEVICES 100
|
||||
#define AHCI_MAPPING_BASE SPECIAL_MEMOEY_MAPPING_VIRT_ADDR_BASE + AHCI_MAPPING_OFFSET
|
||||
|
||||
/// @brief 保留了对 pci设备获取 和 mm内存映射 的依赖
|
||||
void ahci_cpp_init(uint32_t *count_ahci_devices, struct pci_device_structure_header_t *ahci_devs[MAX_AHCI_DEVICES], struct pci_device_structure_general_device_t *gen_devs[MAX_AHCI_DEVICES]);
|
@ -5,9 +5,13 @@ pub mod hba;
|
||||
|
||||
use crate::filesystem::vfs::io::device::BlockDevice;
|
||||
// 依赖的rust工具包
|
||||
use crate::driver::pci::pci::{
|
||||
get_pci_device_structure_mut, PciDeviceStructure, PCI_DEVICE_LINKEDLIST,
|
||||
};
|
||||
use crate::filesystem::devfs::devfs_register;
|
||||
use crate::filesystem::vfs::io::disk_info::BLK_GF_AHCI;
|
||||
use crate::kerror;
|
||||
use crate::libs::rwlock::RwLockWriteGuard;
|
||||
use crate::libs::spinlock::{SpinLock, SpinLockGuard};
|
||||
use crate::mm::virt_2_phys;
|
||||
use crate::syscall::SystemError;
|
||||
@ -20,21 +24,23 @@ use crate::{
|
||||
kdebug,
|
||||
};
|
||||
use ahci_inode::LockedAhciInode;
|
||||
use alloc::boxed::Box;
|
||||
use alloc::string::ToString;
|
||||
use alloc::{format, string::String, sync::Arc, vec::Vec};
|
||||
use core::sync::atomic::compiler_fence;
|
||||
|
||||
// 依赖的C结构体/常量
|
||||
use crate::include::bindings::bindings::{
|
||||
ahci_cpp_init, pci_device_structure_general_device_t, pci_device_structure_header_t,
|
||||
AHCI_MAPPING_BASE, MAX_AHCI_DEVICES, PAGE_2M_MASK,
|
||||
use alloc::{
|
||||
boxed::Box,
|
||||
collections::LinkedList,
|
||||
format,
|
||||
string::{String, ToString},
|
||||
sync::Arc,
|
||||
vec::Vec,
|
||||
};
|
||||
use core::sync::atomic::compiler_fence;
|
||||
|
||||
// 仅module内可见 全局数据区 hbr_port, disks
|
||||
static LOCKED_HBA_MEM_LIST: SpinLock<Vec<&mut HbaMem>> = SpinLock::new(Vec::new());
|
||||
static LOCKED_DISKS_LIST: SpinLock<Vec<Arc<LockedAhciDisk>>> = SpinLock::new(Vec::new());
|
||||
|
||||
const AHCI_CLASS: u8 = 0x1;
|
||||
const AHCI_SUBCLASS: u8 = 0x6;
|
||||
|
||||
/* TFES - Task File Error Status */
|
||||
#[allow(non_upper_case_globals)]
|
||||
pub const HBA_PxIS_TFES: u32 = 1 << 30;
|
||||
@ -48,53 +54,57 @@ pub extern "C" fn ahci_init() -> i32 {
|
||||
return r.unwrap_err().to_posix_errno();
|
||||
}
|
||||
}
|
||||
|
||||
/// @brief 寻找所有的ahci设备
|
||||
/// @param list 链表的写锁
|
||||
/// @return Result<Vec<&'a mut Box<dyn PciDeviceStructure>>, SystemError> 成功则返回包含所有ahci设备结构体的可变引用的链表,失败则返回err
|
||||
fn ahci_device_search<'a>(
|
||||
list: &'a mut RwLockWriteGuard<'_, LinkedList<Box<dyn PciDeviceStructure>>>,
|
||||
) -> Result<Vec<&'a mut Box<dyn PciDeviceStructure>>, SystemError> {
|
||||
let result = get_pci_device_structure_mut(list, AHCI_CLASS, AHCI_SUBCLASS);
|
||||
|
||||
if result.is_empty() {
|
||||
return Err(SystemError::ENODEV);
|
||||
}
|
||||
kdebug!("{}", result.len());
|
||||
Ok(result)
|
||||
}
|
||||
|
||||
/// @brief: 初始化 ahci
|
||||
pub fn ahci_rust_init() -> Result<(), SystemError> {
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
let mut ahci_dev_counts: u32 = 0;
|
||||
let mut ahci_devs: [*mut pci_device_structure_header_t; MAX_AHCI_DEVICES as usize] =
|
||||
[0 as *mut pci_device_structure_header_t; MAX_AHCI_DEVICES as usize];
|
||||
let mut gen_devs: [*mut pci_device_structure_general_device_t; MAX_AHCI_DEVICES as usize] =
|
||||
[0 as *mut pci_device_structure_general_device_t; MAX_AHCI_DEVICES as usize];
|
||||
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
unsafe {
|
||||
// 单线程 init, 所以写 ahci_devs 全局变量不会出错?
|
||||
ahci_cpp_init(
|
||||
(&mut ahci_dev_counts) as *mut u32,
|
||||
(&mut ahci_devs) as *mut *mut pci_device_structure_header_t,
|
||||
(&mut gen_devs) as *mut *mut pci_device_structure_general_device_t,
|
||||
);
|
||||
}
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
let mut list = PCI_DEVICE_LINKEDLIST.write();
|
||||
let ahci_device = ahci_device_search(&mut list)?;
|
||||
// 全局数据 - 列表
|
||||
let mut disks_list = LOCKED_DISKS_LIST.lock();
|
||||
|
||||
for i in 0..(ahci_dev_counts as usize) {
|
||||
for device in ahci_device {
|
||||
let standard_device = device.as_standard_device_mut().unwrap();
|
||||
standard_device.bar_ioremap();
|
||||
// 对于每一个ahci控制器分配一块空间 (目前slab algorithm最大支持1MB)
|
||||
let ahci_port_base_vaddr =
|
||||
Box::leak(Box::new([0u8; (1 << 20) as usize])) as *mut u8 as usize;
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
// 获取全局引用 : 计算 HBA_MEM 的虚拟地址 依赖于C的宏定义 cal_HBA_MEM_VIRT_ADDR
|
||||
let virt_addr = AHCI_MAPPING_BASE as usize + unsafe { (*gen_devs[i]).BAR5 as usize }
|
||||
- (unsafe { (*gen_devs[0]).BAR5 as usize } & PAGE_2M_MASK as usize);
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
let virtaddr = standard_device
|
||||
.bar()
|
||||
.ok_or(SystemError::EACCES)?
|
||||
.get_bar(5)
|
||||
.or(Err(SystemError::EACCES))?
|
||||
.virtual_address()
|
||||
.unwrap();
|
||||
// 最后把这个引用列表放入到全局列表
|
||||
let mut hba_mem_list = LOCKED_HBA_MEM_LIST.lock();
|
||||
hba_mem_list.push(unsafe { (virt_addr as *mut HbaMem).as_mut().unwrap() });
|
||||
let pi = volatile_read!(hba_mem_list[i].pi);
|
||||
//这里两次unsafe转引用规避rust只能有一个可变引用的检查,提高运行速度
|
||||
let hba_mem = unsafe { (virtaddr as *mut HbaMem).as_mut().unwrap() };
|
||||
hba_mem_list.push(unsafe { (virtaddr as *mut HbaMem).as_mut().unwrap() });
|
||||
let pi = volatile_read!(hba_mem.pi);
|
||||
let hba_mem_index = hba_mem_list.len() - 1;
|
||||
drop(hba_mem_list);
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
// 初始化所有的port
|
||||
let mut id = 0;
|
||||
for j in 0..32 {
|
||||
if (pi >> j) & 1 > 0 {
|
||||
let mut hba_mem_list = LOCKED_HBA_MEM_LIST.lock();
|
||||
let tp = hba_mem_list[i].ports[j].check_type();
|
||||
let hba_mem_list = LOCKED_HBA_MEM_LIST.lock();
|
||||
let hba_mem_port = &mut hba_mem.ports[j];
|
||||
let tp = hba_mem_port.check_type();
|
||||
match tp {
|
||||
HbaPortType::None => {
|
||||
kdebug!("<ahci_rust_init> Find a None type Disk.");
|
||||
@ -108,7 +118,6 @@ pub fn ahci_rust_init() -> Result<(), SystemError> {
|
||||
// 计算地址
|
||||
let fb = virt_2_phys(ahci_port_base_vaddr + (32 << 10) + (j << 8));
|
||||
let clb = virt_2_phys(ahci_port_base_vaddr + (j << 10));
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
let ctbas = (0..32)
|
||||
.map(|x| {
|
||||
virt_2_phys(
|
||||
@ -118,17 +127,14 @@ pub fn ahci_rust_init() -> Result<(), SystemError> {
|
||||
.collect::<Vec<_>>();
|
||||
|
||||
// 初始化 port
|
||||
hba_mem_list[i].ports[j].init(clb as u64, fb as u64, &ctbas);
|
||||
|
||||
// 释放锁
|
||||
hba_mem_port.init(clb as u64, fb as u64, &ctbas);
|
||||
drop(hba_mem_list);
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
// 创建 disk
|
||||
disks_list.push(LockedAhciDisk::new(
|
||||
format!("ahci_disk_{}", id),
|
||||
BLK_GF_AHCI,
|
||||
i as u8,
|
||||
hba_mem_index as u8,
|
||||
j as u8,
|
||||
)?);
|
||||
id += 1; // ID 从0开始
|
||||
@ -144,7 +150,7 @@ pub fn ahci_rust_init() -> Result<(), SystemError> {
|
||||
kerror!(
|
||||
"Ahci_{} ctrl = {}, port = {} failed to register, error code = {:?}",
|
||||
id,
|
||||
i,
|
||||
hba_mem_index as u8,
|
||||
j,
|
||||
err
|
||||
);
|
||||
@ -168,23 +174,20 @@ pub fn disks() -> Vec<Arc<LockedAhciDisk>> {
|
||||
|
||||
/// @brief: 通过 name 获取 disk
|
||||
pub fn get_disks_by_name(name: String) -> Result<Arc<LockedAhciDisk>, SystemError> {
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
let disks_list: SpinLockGuard<Vec<Arc<LockedAhciDisk>>> = LOCKED_DISKS_LIST.lock();
|
||||
for i in 0..disks_list.len() {
|
||||
if disks_list[i].0.lock().name == name {
|
||||
return Ok(disks_list[i].clone());
|
||||
}
|
||||
}
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
return Err(SystemError::ENXIO);
|
||||
let result = disks_list
|
||||
.iter()
|
||||
.find(|x| x.0.lock().name == name)
|
||||
.ok_or(SystemError::ENXIO)?
|
||||
.clone();
|
||||
return Ok(result);
|
||||
}
|
||||
|
||||
/// @brief: 通过 ctrl_num 和 port_num 获取 port
|
||||
pub fn _port(ctrl_num: u8, port_num: u8) -> &'static mut HbaPort {
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
fn _port(ctrl_num: u8, port_num: u8) -> &'static mut HbaPort {
|
||||
let list: SpinLockGuard<Vec<&mut HbaMem>> = LOCKED_HBA_MEM_LIST.lock();
|
||||
let port: &HbaPort = &list[ctrl_num as usize].ports[port_num as usize];
|
||||
compiler_fence(core::sync::atomic::Ordering::SeqCst);
|
||||
|
||||
return unsafe { (port as *const HbaPort as *mut HbaPort).as_mut().unwrap() };
|
||||
}
|
||||
|
||||
|
@ -1,14 +1,9 @@
|
||||
|
||||
all: pci.o pci_irq.o msi.o
|
||||
all: pci_irq.o
|
||||
|
||||
CFLAGS += -I .
|
||||
|
||||
pci.o: pci.c
|
||||
$(CC) $(CFLAGS) -c pci.c -o pci.o
|
||||
|
||||
pci_irq.o: pci_irq.c
|
||||
$(CC) $(CFLAGS) -c pci_irq.c -o pci_irq.o
|
||||
|
||||
msi.o: msi.c
|
||||
$(CC) $(CFLAGS) -c msi.c -o msi.o
|
||||
|
||||
|
@ -1,340 +0,0 @@
|
||||
#include "msi.h"
|
||||
#include "pci.h"
|
||||
#include <common/errno.h>
|
||||
#include <mm/mmio.h>
|
||||
|
||||
/**
|
||||
* @brief 生成msi消息
|
||||
*
|
||||
* @param msi_desc msi描述符
|
||||
* @return struct msi_msg_t* msi消息指针(在描述符内)
|
||||
*/
|
||||
extern struct msi_msg_t *msi_arch_get_msg(struct msi_desc_t *msi_desc);
|
||||
|
||||
/**
|
||||
* @brief 读取msix的capability list
|
||||
*
|
||||
* @param msi_desc msi描述符
|
||||
* @param cap_off capability list的offset
|
||||
* @return struct pci_msix_cap_t 对应的capability list
|
||||
*/
|
||||
static __always_inline struct pci_msix_cap_t __msi_read_msix_cap_list(struct msi_desc_t *msi_desc, uint32_t cap_off)
|
||||
{
|
||||
struct pci_msix_cap_t cap_list = {0};
|
||||
uint32_t dw0;
|
||||
dw0 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off);
|
||||
io_lfence();
|
||||
cap_list.cap_id = dw0 & 0xff;
|
||||
cap_list.next_off = (dw0 >> 8) & 0xff;
|
||||
cap_list.msg_ctrl = (dw0 >> 16) & 0xffff;
|
||||
|
||||
cap_list.dword1 =
|
||||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x4);
|
||||
cap_list.dword2 =
|
||||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x8);
|
||||
return cap_list;
|
||||
}
|
||||
|
||||
static __always_inline struct pci_msi_cap_t __msi_read_cap_list(struct msi_desc_t *msi_desc, uint32_t cap_off)
|
||||
{
|
||||
struct pci_msi_cap_t cap_list = {0};
|
||||
uint32_t dw0;
|
||||
dw0 = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off);
|
||||
cap_list.cap_id = dw0 & 0xff;
|
||||
cap_list.next_off = (dw0 >> 8) & 0xff;
|
||||
cap_list.msg_ctrl = (dw0 >> 16) & 0xffff;
|
||||
|
||||
cap_list.msg_addr_lo =
|
||||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x4);
|
||||
uint16_t msg_data_off = 0xc;
|
||||
if (cap_list.msg_ctrl & (1 << 7)) // 64位
|
||||
{
|
||||
cap_list.msg_addr_hi =
|
||||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x8);
|
||||
}
|
||||
else
|
||||
{
|
||||
cap_list.msg_addr_hi = 0;
|
||||
msg_data_off = 0x8;
|
||||
}
|
||||
|
||||
cap_list.msg_data = pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func,
|
||||
cap_off + msg_data_off) &
|
||||
0xffff;
|
||||
|
||||
cap_list.mask =
|
||||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x10);
|
||||
cap_list.pending =
|
||||
pci_read_config(msi_desc->pci_dev->bus, msi_desc->pci_dev->device, msi_desc->pci_dev->func, cap_off + 0x14);
|
||||
|
||||
return cap_list;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 映射设备的msix表 //MSIX表不再单独映射(To do)
|
||||
*
|
||||
* @param pci_dev pci设备信息结构体
|
||||
* @param msix_cap msix capability list的结构体
|
||||
* @return int 错误码
|
||||
*/
|
||||
static __always_inline int __msix_map_table(struct pci_device_structure_header_t *pci_dev,
|
||||
struct pci_msix_cap_t *msix_cap)
|
||||
{
|
||||
// 计算bar寄存器的offset
|
||||
uint32_t bar_off = 0x10 + 4 * (msix_cap->dword1 & 0x7);
|
||||
|
||||
// msix table相对于bar寄存器中存储的地址的offset
|
||||
pci_dev->msix_offset = msix_cap->dword1 & (~0x7);
|
||||
pci_dev->msix_table_size = (msix_cap->msg_ctrl & 0x7ff) + 1;
|
||||
pci_dev->msix_mmio_size = pci_dev->msix_table_size * 16 + pci_dev->msix_offset;
|
||||
|
||||
// 申请mmio空间
|
||||
mmio_create(pci_dev->msix_mmio_size, VM_IO | VM_DONTCOPY, &pci_dev->msix_mmio_vaddr, &pci_dev->msix_mmio_size);
|
||||
pci_dev->msix_mmio_vaddr &= (~0xf);
|
||||
uint32_t bar = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->func, bar_off);
|
||||
// kdebug("pci_dev->msix_mmio_vaddr=%#018lx, bar=%#010lx, table offset=%#010lx, table_size=%#010lx, mmio_size=%d",
|
||||
// pci_dev->msix_mmio_vaddr, bar, pci_dev->msix_offset, pci_dev->msix_table_size, pci_dev->msix_mmio_size);
|
||||
|
||||
// 将msix table映射到页表
|
||||
rs_map_phys(pci_dev->msix_mmio_vaddr, bar, pci_dev->msix_mmio_size, PAGE_KERNEL_PAGE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 将msi_desc中的数据填写到msix表的指定表项处
|
||||
*
|
||||
* @param pci_dev pci设备结构体
|
||||
* @param msi_desc msi描述符
|
||||
*/
|
||||
static __always_inline void __msix_set_entry(struct msi_desc_t *msi_desc)
|
||||
{
|
||||
uint64_t *ptr =
|
||||
(uint64_t *)(msi_desc->pci_dev->msix_mmio_vaddr + msi_desc->pci_dev->msix_offset + msi_desc->msi_index * 16);
|
||||
*ptr = ((uint64_t)(msi_desc->msg.address_hi) << 32) | (msi_desc->msg.address_lo);
|
||||
io_mfence();
|
||||
++ptr;
|
||||
io_mfence();
|
||||
*ptr = ((uint64_t)(msi_desc->msg.vector_control) << 32) | (msi_desc->msg.data);
|
||||
io_mfence();
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 清空设备的msix table的指定表项
|
||||
*
|
||||
* @param pci_dev pci设备
|
||||
* @param msi_index 表项号
|
||||
*/
|
||||
static __always_inline void __msix_clear_entry(struct pci_device_structure_header_t *pci_dev, uint16_t msi_index)
|
||||
{
|
||||
uint64_t *ptr = (uint64_t *)(pci_dev->msix_mmio_vaddr + pci_dev->msix_offset + msi_index * 16);
|
||||
*ptr = 0;
|
||||
++ptr;
|
||||
*ptr = 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 启用 Message Signaled Interrupts
|
||||
*
|
||||
* @param header 设备header
|
||||
* @param vector 中断向量号
|
||||
* @param processor 要投递到的处理器
|
||||
* @param edge_trigger 是否边缘触发
|
||||
* @param assert 是否高电平触发
|
||||
*
|
||||
* @return 返回码
|
||||
*/
|
||||
int pci_enable_msi(struct msi_desc_t *msi_desc)
|
||||
{
|
||||
struct pci_device_structure_header_t *ptr = msi_desc->pci_dev;
|
||||
uint32_t cap_ptr;
|
||||
uint32_t tmp;
|
||||
uint16_t message_control;
|
||||
uint64_t message_addr;
|
||||
|
||||
// 先尝试获取msi-x,若不存在,则获取msi capability
|
||||
if (msi_desc->pci.msi_attribute.is_msix)
|
||||
{
|
||||
cap_ptr = pci_enumerate_capability_list(ptr, 0x11);
|
||||
if (((int32_t)cap_ptr) < 0)
|
||||
{
|
||||
cap_ptr = pci_enumerate_capability_list(ptr, 0x05);
|
||||
if (((int32_t)cap_ptr) < 0)
|
||||
return -ENOSYS;
|
||||
msi_desc->pci.msi_attribute.is_msix = 0;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
cap_ptr = pci_enumerate_capability_list(ptr, 0x05);
|
||||
if (((int32_t)cap_ptr) < 0)
|
||||
return -ENOSYS;
|
||||
msi_desc->pci.msi_attribute.is_msix = 0;
|
||||
}
|
||||
// 获取msi消息
|
||||
msi_arch_get_msg(msi_desc);
|
||||
|
||||
if (msi_desc->pci.msi_attribute.is_msix) // MSI-X
|
||||
{
|
||||
kdebug("is msix");
|
||||
// 读取msix的信息
|
||||
struct pci_msix_cap_t cap = __msi_read_msix_cap_list(msi_desc, cap_ptr);
|
||||
// 映射msix table
|
||||
__msix_map_table(msi_desc->pci_dev, &cap);
|
||||
io_mfence();
|
||||
// 设置msix的中断
|
||||
__msix_set_entry(msi_desc);
|
||||
io_mfence();
|
||||
|
||||
// todo: disable intx
|
||||
// 使能msi-x
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
tmp |= (1U << 31);
|
||||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||||
}
|
||||
else
|
||||
{
|
||||
kdebug("is msi");
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
message_control = (tmp >> 16) & 0xffff;
|
||||
|
||||
// 写入message address
|
||||
message_addr = ((((uint64_t)msi_desc->msg.address_hi) << 32) | msi_desc->msg.address_lo); // 获取message address
|
||||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x4, (uint32_t)(message_addr & 0xffffffff));
|
||||
|
||||
if (message_control & (1 << 7)) // 64位
|
||||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8,
|
||||
(uint32_t)((message_addr >> 32) & 0xffffffff));
|
||||
|
||||
// 写入message data
|
||||
|
||||
tmp = msi_desc->msg.data;
|
||||
if (message_control & (1 << 7)) // 64位
|
||||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0xc, tmp);
|
||||
else
|
||||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr + 0x8, tmp);
|
||||
|
||||
// 使能msi
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
tmp |= (1 << 16);
|
||||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 在已配置好msi寄存器的设备上,使能msi
|
||||
*
|
||||
* @param header 设备头部
|
||||
* @return int 返回码
|
||||
*/
|
||||
int pci_start_msi(void *header)
|
||||
{
|
||||
struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
|
||||
uint32_t cap_ptr;
|
||||
uint32_t tmp;
|
||||
|
||||
switch (ptr->HeaderType)
|
||||
{
|
||||
case 0x00: // general device
|
||||
if (!(ptr->Status & 0x10))
|
||||
return -ENOSYS;
|
||||
cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
|
||||
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
|
||||
if (tmp & 0xff != 0x5)
|
||||
return -ENOSYS;
|
||||
|
||||
// 使能msi
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
tmp |= (1 << 16);
|
||||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||||
|
||||
break;
|
||||
|
||||
case 0x01: // pci to pci bridge
|
||||
if (!(ptr->Status & 0x10))
|
||||
return -ENOSYS;
|
||||
cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
|
||||
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
|
||||
if (tmp & 0xff != 0x5)
|
||||
return -ENOSYS;
|
||||
|
||||
// 使能msi
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
tmp |= (1 << 16);
|
||||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||||
|
||||
break;
|
||||
case 0x02: // pci to card bus bridge
|
||||
return -ENOSYS;
|
||||
break;
|
||||
|
||||
default: // 不应该到达这里
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
/**
|
||||
* @brief 禁用指定设备的msi
|
||||
*
|
||||
* @param header pci header
|
||||
* @return int
|
||||
*/
|
||||
int pci_disable_msi(void *header)
|
||||
{
|
||||
struct pci_device_structure_header_t *ptr = (struct pci_device_structure_header_t *)header;
|
||||
uint32_t cap_ptr;
|
||||
uint32_t tmp;
|
||||
|
||||
switch (ptr->HeaderType)
|
||||
{
|
||||
case 0x00: // general device
|
||||
if (!(ptr->Status & 0x10))
|
||||
return -ENOSYS;
|
||||
cap_ptr = ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer;
|
||||
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
|
||||
if (tmp & 0xff != 0x5)
|
||||
return -ENOSYS;
|
||||
|
||||
// 禁用msi
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
tmp &= (~(1 << 16));
|
||||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||||
|
||||
break;
|
||||
|
||||
case 0x01: // pci to pci bridge
|
||||
if (!(ptr->Status & 0x10))
|
||||
return -ENOSYS;
|
||||
cap_ptr = ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer;
|
||||
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
|
||||
if (tmp & 0xff != 0x5)
|
||||
return -ENOSYS;
|
||||
|
||||
// 禁用msi
|
||||
tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, cap_ptr); // 读取cap+0x0处的值
|
||||
tmp &= (~(1 << 16));
|
||||
pci_write_config(ptr->bus, ptr->device, ptr->func, cap_ptr, tmp);
|
||||
|
||||
break;
|
||||
case 0x02: // pci to card bus bridge
|
||||
return -ENOSYS;
|
||||
break;
|
||||
|
||||
default: // 不应该到达这里
|
||||
return -EINVAL;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
@ -1,110 +0,0 @@
|
||||
#pragma once
|
||||
#include <common/glib.h>
|
||||
|
||||
/**
|
||||
* @brief msi消息内容结构体
|
||||
*
|
||||
*/
|
||||
struct msi_msg_t
|
||||
{
|
||||
uint32_t address_lo;
|
||||
uint32_t address_hi;
|
||||
uint32_t data;
|
||||
uint32_t vector_control;
|
||||
};
|
||||
struct pci_msi_desc_t
|
||||
{
|
||||
union
|
||||
{
|
||||
uint32_t msi_mask; // [PCI MSI] MSI cached mask bits
|
||||
uint32_t msix_ctrl; // [PCI MSI-X] MSI-X cached per vector control bits
|
||||
};
|
||||
|
||||
struct
|
||||
{
|
||||
uint8_t is_msix : 1; // [PCI MSI/X] True if MSI-X
|
||||
uint8_t can_mask : 1; // [PCI MSI/X] Masking supported?
|
||||
uint8_t is_64 : 1; // [PCI MSI/X] Address size: 0=32bit 1=64bit
|
||||
} msi_attribute;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief msi capability list的结构
|
||||
*
|
||||
*/
|
||||
struct pci_msi_cap_t
|
||||
{
|
||||
uint8_t cap_id;
|
||||
uint8_t next_off;
|
||||
uint16_t msg_ctrl;
|
||||
|
||||
uint32_t msg_addr_lo;
|
||||
uint32_t msg_addr_hi;
|
||||
|
||||
uint16_t msg_data;
|
||||
uint16_t Rsvd;
|
||||
|
||||
uint32_t mask;
|
||||
uint32_t pending;
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief MSI-X的capability list结构体
|
||||
*
|
||||
*/
|
||||
struct pci_msix_cap_t
|
||||
{
|
||||
uint8_t cap_id;
|
||||
uint8_t next_off;
|
||||
uint16_t msg_ctrl;
|
||||
|
||||
uint32_t dword1; // 该DWORD的组成为:[Table Offset][BIR2:0].
|
||||
// 由于Table Offset是8字节对齐的,因此mask掉该dword的BIR部分,就是table offset的值
|
||||
uint32_t dword2; // 该DWORD的组成为:[Pending Bit Offset][Pending Bit BIR2:0].
|
||||
// 由于Pending Bit Offset是8字节对齐的,因此mask掉该dword的BIR部分,就是Pending Bit Offset的值
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief msi描述符
|
||||
*
|
||||
*/
|
||||
struct msi_desc_t
|
||||
{
|
||||
uint16_t irq_num; // 中断向量号
|
||||
uint16_t processor; // 定向投递的处理器
|
||||
uint16_t edge_trigger; // 是否边缘触发
|
||||
uint16_t assert; // 是否高电平触发
|
||||
struct pci_device_structure_header_t *pci_dev; // 对应的pci设备的结构体
|
||||
struct msi_msg_t msg; // msi消息
|
||||
uint16_t msi_index; // msi描述符的index
|
||||
struct pci_msi_desc_t pci; // 与pci相关的msi描述符数据
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 启用 Message Signaled Interrupts
|
||||
*
|
||||
* @param header 设备header
|
||||
* @param vector 中断向量号
|
||||
* @param processor 要投递到的处理器
|
||||
* @param edge_trigger 是否边缘触发
|
||||
* @param assert 是否高电平触发
|
||||
*
|
||||
* @return 返回码
|
||||
*/
|
||||
int pci_enable_msi(struct msi_desc_t *msi_desc);
|
||||
|
||||
/**
|
||||
* @brief 禁用指定设备的msi
|
||||
*
|
||||
* @param header pci header
|
||||
* @return int
|
||||
*/
|
||||
int pci_disable_msi(void *header);
|
||||
|
||||
/**
|
||||
* @brief 在已配置好msi寄存器的设备上,使能msi
|
||||
*
|
||||
* @param header 设备头部
|
||||
* @return int 返回码
|
||||
*/
|
||||
int pci_start_msi(void *header);
|
@ -1,542 +0,0 @@
|
||||
#include "pci.h"
|
||||
#include <common/kprint.h>
|
||||
#include <mm/slab.h>
|
||||
#include <debug/bug.h>
|
||||
#include <common/errno.h>
|
||||
|
||||
static uint count_device_list = 0;
|
||||
static void pci_checkBus(uint8_t bus);
|
||||
|
||||
/**
|
||||
* @brief 将设备信息结构体加到链表里面
|
||||
*
|
||||
*/
|
||||
#define ADD_DEVICE_STRUCT_TO_LIST(ret) \
|
||||
do \
|
||||
{ \
|
||||
if (count_device_list > 0) \
|
||||
{ \
|
||||
++count_device_list; \
|
||||
list_add(pci_device_structure_list, &(ret->header.list)); \
|
||||
} \
|
||||
else \
|
||||
{ \
|
||||
++count_device_list; \
|
||||
list_init(&(ret->header.list)); \
|
||||
pci_device_structure_list = &(ret->header.list); \
|
||||
} \
|
||||
} while (0)
|
||||
|
||||
|
||||
/**
|
||||
* @brief 从pci配置空间读取信息
|
||||
*
|
||||
* @param bus 总线号
|
||||
* @param slot 设备号
|
||||
* @param func 功能号
|
||||
* @param offset 字节偏移量
|
||||
* @return uint 寄存器值
|
||||
*/
|
||||
uint32_t pci_read_config(uchar bus, uchar slot, uchar func, uchar offset)
|
||||
{
|
||||
uint lbus = (uint)bus;
|
||||
uint lslot = (uint)slot;
|
||||
uint lfunc = ((uint)func) & 7;
|
||||
|
||||
// 构造pci配置空间地址
|
||||
uint address = (uint)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xfc) | ((uint)0x80000000));
|
||||
io_out32(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
// 读取返回的数据
|
||||
uint32_t ret = (uint)(io_in32(PORT_PCI_CONFIG_DATA));
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 向pci配置空间写入信息
|
||||
*
|
||||
* @param bus 总线号
|
||||
* @param slot 设备号
|
||||
* @param func 功能号
|
||||
* @param offset 字节偏移量
|
||||
* @return uint 返回码
|
||||
*/
|
||||
uint pci_write_config(uchar bus, uchar slot, uchar func, uchar offset, uint32_t data)
|
||||
{
|
||||
uint lbus = (uint)bus;
|
||||
uint lslot = (uint)slot;
|
||||
uint lfunc = ((uint)func) & 7;
|
||||
|
||||
// 构造pci配置空间地址
|
||||
uint address = (uint)((lbus << 16) | (lslot << 11) | (lfunc << 8) | (offset & 0xfc) | ((uint)0x80000000));
|
||||
io_out32(PORT_PCI_CONFIG_ADDRESS, address);
|
||||
|
||||
// 写入数据
|
||||
io_out32(PORT_PCI_CONFIG_DATA, data);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取type为0x0的pci设备的header
|
||||
* 本函数只应被 pci_read_header()调用
|
||||
* @param header 返回的header
|
||||
* @param bus 总线号
|
||||
* @param slot 插槽号
|
||||
* @param func 功能号
|
||||
*/
|
||||
static void pci_read_general_device_header(struct pci_device_structure_general_device_t *header, uchar bus, uchar slot, uchar func)
|
||||
{
|
||||
uint32_t tmp32;
|
||||
header->BAR0 = pci_read_config(bus, slot, func, 0x10);
|
||||
header->BAR1 = pci_read_config(bus, slot, func, 0x14);
|
||||
header->BAR2 = pci_read_config(bus, slot, func, 0x18);
|
||||
header->BAR3 = pci_read_config(bus, slot, func, 0x1c);
|
||||
header->BAR4 = pci_read_config(bus, slot, func, 0x20);
|
||||
header->BAR5 = pci_read_config(bus, slot, func, 0x24);
|
||||
header->Cardbus_CIS_Pointer = pci_read_config(bus, slot, func, 0x28);
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x2c);
|
||||
header->Subsystem_Vendor_ID = tmp32 & 0xffff;
|
||||
header->Subsystem_ID = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
header->Expansion_ROM_base_address = pci_read_config(bus, slot, func, 0x30);
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x34);
|
||||
header->Capabilities_Pointer = tmp32 & 0xff;
|
||||
header->reserved0 = (tmp32 >> 8) & 0xff;
|
||||
header->reserved1 = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
header->reserved2 = pci_read_config(bus, slot, func, 0x38);
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x3c);
|
||||
header->Interrupt_Line = tmp32 & 0xff;
|
||||
header->Interrupt_PIN = (tmp32 >> 8) & 0xff;
|
||||
header->Min_Grant = (tmp32 >> 16) & 0xff;
|
||||
header->Max_Latency = (tmp32 >> 24) & 0xff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取type为0x1的pci_to_pci_bridge的header
|
||||
* 本函数只应被 pci_read_header()调用
|
||||
* @param header 返回的header
|
||||
* @param bus 总线号
|
||||
* @param slot 插槽号
|
||||
* @param func 功能号
|
||||
*/
|
||||
static void pci_read_pci_to_pci_bridge_header(struct pci_device_structure_pci_to_pci_bridge_t *header, uchar bus, uchar slot, uchar func)
|
||||
{
|
||||
uint32_t tmp32;
|
||||
header->BAR0 = pci_read_config(bus, slot, func, 0x10);
|
||||
header->BAR1 = pci_read_config(bus, slot, func, 0x14);
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x18);
|
||||
|
||||
header->Primary_Bus_Number = tmp32 & 0xff;
|
||||
header->Secondary_Bus_Number = (tmp32 >> 8) & 0xff;
|
||||
header->Subordinate_Bus_Number = (tmp32 >> 16) & 0xff;
|
||||
header->Secondary_Latency_Timer = (tmp32 >> 24) & 0xff;
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x1c);
|
||||
header->io_base = tmp32 & 0xff;
|
||||
header->io_limit = (tmp32 >> 8) & 0xff;
|
||||
header->Secondary_Status = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x20);
|
||||
header->Memory_Base = tmp32 & 0xffff;
|
||||
header->Memory_Limit = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x24);
|
||||
header->Prefetchable_Memory_Base = tmp32 & 0xffff;
|
||||
header->Prefetchable_Memory_Limit = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
header->Prefetchable_Base_Upper_32_Bits = pci_read_config(bus, slot, func, 0x28);
|
||||
header->Prefetchable_Limit_Upper_32_Bits = pci_read_config(bus, slot, func, 0x2c);
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x30);
|
||||
header->io_Base_Upper_16_Bits = tmp32 & 0xffff;
|
||||
header->io_Limit_Upper_16_Bits = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x34);
|
||||
header->Capability_Pointer = tmp32 & 0xff;
|
||||
header->reserved0 = (tmp32 >> 8) & 0xff;
|
||||
header->reserved1 = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
header->Expansion_ROM_base_address = pci_read_config(bus, slot, func, 0x38);
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x3c);
|
||||
header->Interrupt_Line = tmp32 & 0xff;
|
||||
header->Interrupt_PIN = (tmp32 >> 8) & 0xff;
|
||||
header->Bridge_Control = (tmp32 >> 16) & 0xffff;
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取type为0x2的pci_to_cardbus_bridge的header
|
||||
* 本函数只应被 pci_read_header()调用
|
||||
* @param header 返回的header
|
||||
* @param bus 总线号
|
||||
* @param slot 插槽号
|
||||
* @param func 功能号
|
||||
*/
|
||||
static void pci_read_pci_to_cardbus_bridge_header(struct pci_device_structure_pci_to_cardbus_bridge_t *header, uchar bus, uchar slot, uchar func)
|
||||
{
|
||||
uint32_t tmp32;
|
||||
|
||||
header->CardBus_Socket_ExCa_base_address = pci_read_config(bus, slot, func, 0x10);
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x14);
|
||||
header->Offset_of_capabilities_list = tmp32 & 0xff;
|
||||
header->Reserved = (tmp32 >> 8) & 0xff;
|
||||
header->Secondary_status = (tmp32 >> 16) & 0xff;
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x18);
|
||||
header->PCI_bus_number = tmp32 & 0xff;
|
||||
header->CardBus_bus_number = (tmp32 >> 8) & 0xff;
|
||||
header->Subordinate_bus_number = (tmp32 >> 16) & 0xff;
|
||||
header->CardBus_latency_timer = (tmp32 >> 24) & 0xff;
|
||||
|
||||
header->Memory_Base_Address0 = pci_read_config(bus, slot, func, 0x1c);
|
||||
header->Memory_Limit0 = pci_read_config(bus, slot, func, 0x20);
|
||||
header->Memory_Base_Address1 = pci_read_config(bus, slot, func, 0x24);
|
||||
header->Memory_Limit1 = pci_read_config(bus, slot, func, 0x28);
|
||||
|
||||
header->IO_Base_Address0 = pci_read_config(bus, slot, func, 0x2c);
|
||||
header->IO_Limit0 = pci_read_config(bus, slot, func, 0x30);
|
||||
header->IO_Base_Address1 = pci_read_config(bus, slot, func, 0x34);
|
||||
header->IO_Limit1 = pci_read_config(bus, slot, func, 0x38);
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x3c);
|
||||
header->Interrupt_Line = tmp32 & 0xff;
|
||||
header->Interrupt_PIN = (tmp32 >> 8) & 0xff;
|
||||
header->Bridge_Control = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x40);
|
||||
header->Subsystem_Device_ID = tmp32 & 0xffff;
|
||||
header->Subsystem_Vendor_ID = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
header->PC_Card_legacy_mode_base_address_16_bit = pci_read_config(bus, slot, func, 0x44);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 读取pci设备标头
|
||||
*
|
||||
* @param type 标头类型
|
||||
* @param bus 总线号
|
||||
* @param slot 插槽号
|
||||
* @param func 功能号
|
||||
* @param add_to_list 添加到链表
|
||||
* @return 返回的header
|
||||
*/
|
||||
void *pci_read_header(int *type, uchar bus, uchar slot, uchar func, bool add_to_list)
|
||||
{
|
||||
struct pci_device_structure_header_t *common_header = (struct pci_device_structure_header_t *)kmalloc(127, 0);
|
||||
common_header->bus = bus;
|
||||
common_header->device = slot;
|
||||
common_header->func = func;
|
||||
|
||||
uint32_t tmp32;
|
||||
// 先读取公共header
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x0);
|
||||
common_header->Vendor_ID = tmp32 & 0xffff;
|
||||
common_header->Device_ID = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x4);
|
||||
common_header->Command = tmp32 & 0xffff;
|
||||
common_header->Status = (tmp32 >> 16) & 0xffff;
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0x8);
|
||||
common_header->RevisionID = tmp32 & 0xff;
|
||||
common_header->ProgIF = (tmp32 >> 8) & 0xff;
|
||||
common_header->SubClass = (tmp32 >> 16) & 0xff;
|
||||
common_header->Class_code = (tmp32 >> 24) & 0xff;
|
||||
|
||||
tmp32 = pci_read_config(bus, slot, func, 0xc);
|
||||
common_header->CacheLineSize = tmp32 & 0xff;
|
||||
common_header->LatencyTimer = (tmp32 >> 8) & 0xff;
|
||||
common_header->HeaderType = (tmp32 >> 16) & 0xff;
|
||||
common_header->BIST = (tmp32 >> 24) & 0xff;
|
||||
|
||||
void *ret;
|
||||
if (common_header->Vendor_ID == 0xffff)
|
||||
{
|
||||
*type = -ENXIO;
|
||||
kfree(common_header);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// 根据公共头部,判断该结构所属的类型
|
||||
switch (common_header->HeaderType)
|
||||
{
|
||||
case 0x0: // general device
|
||||
ret = common_header;
|
||||
|
||||
pci_read_general_device_header((struct pci_device_structure_general_device_t *)ret, bus, slot, func);
|
||||
if (add_to_list)
|
||||
ADD_DEVICE_STRUCT_TO_LIST(((struct pci_device_structure_general_device_t *)ret));
|
||||
|
||||
*type = 0x0;
|
||||
return ret;
|
||||
break;
|
||||
case 0x1:
|
||||
ret = common_header;
|
||||
pci_read_pci_to_pci_bridge_header((struct pci_device_structure_pci_to_pci_bridge_t *)ret, bus, slot, func);
|
||||
if (add_to_list)
|
||||
ADD_DEVICE_STRUCT_TO_LIST(((struct pci_device_structure_pci_to_pci_bridge_t *)ret));
|
||||
|
||||
*type = 0x1;
|
||||
return ret;
|
||||
break;
|
||||
case 0x2:
|
||||
ret = common_header;
|
||||
pci_read_pci_to_cardbus_bridge_header((struct pci_device_structure_pci_to_cardbus_bridge_t *)ret, bus, slot, func);
|
||||
if (add_to_list)
|
||||
ADD_DEVICE_STRUCT_TO_LIST(((struct pci_device_structure_pci_to_cardbus_bridge_t *)ret));
|
||||
|
||||
*type = 0x2;
|
||||
return ret;
|
||||
break;
|
||||
default: // 错误的头类型 这里不应该被执行
|
||||
// kerror("PCI->pci_read_header(): Invalid header type.");
|
||||
*type = -EINVAL;
|
||||
// kerror("vendor id=%#010lx", common_header->Vendor_ID);
|
||||
// kerror("header type = %d", common_header->HeaderType);
|
||||
kfree(common_header);
|
||||
return NULL;
|
||||
break;
|
||||
}
|
||||
}
|
||||
static void pci_checkFunction(uint8_t bus, uint8_t device, uint8_t function)
|
||||
{
|
||||
int header_type;
|
||||
struct pci_device_structure_header_t *header = pci_read_header(&header_type, bus, device, function, true);
|
||||
|
||||
if (header_type == -EINVAL)
|
||||
{
|
||||
// kerror("pci_checkFunction(): wrong header type!");
|
||||
// 此处内存已经在read header函数里面释放,不用重复释放
|
||||
return;
|
||||
}
|
||||
// header = ((struct pci_device_structure_general_device_t *)raw_header)->header;
|
||||
|
||||
if ((header->Class_code == 0x6) && (header->SubClass == 0x4))
|
||||
{
|
||||
uint8_t SecondaryBus = ((struct pci_device_structure_pci_to_pci_bridge_t *)header)->Secondary_Bus_Number;
|
||||
pci_checkBus(SecondaryBus);
|
||||
}
|
||||
}
|
||||
|
||||
static int pci_checkDevice(uint8_t bus, uint8_t device)
|
||||
{
|
||||
int header_type;
|
||||
|
||||
struct pci_device_structure_header_t *header = pci_read_header(&header_type, bus, device, 0, false);
|
||||
if (header_type == -EINVAL)
|
||||
{
|
||||
// 此处内存已经在read header函数里面释放,不用重复释放
|
||||
return -EINVAL;
|
||||
}
|
||||
if (header_type == -ENXIO)
|
||||
{
|
||||
// kerror("DEVICE INVALID");
|
||||
return -ENXIO;
|
||||
}
|
||||
|
||||
uint16_t vendorID = header->Vendor_ID;
|
||||
|
||||
if (vendorID == 0xffff) // 设备不存在
|
||||
{
|
||||
kfree(header);
|
||||
return -ENXIO;
|
||||
}
|
||||
pci_checkFunction(bus, device, 0);
|
||||
|
||||
header_type = header->HeaderType;
|
||||
if ((header_type & 0x80) != 0)
|
||||
{
|
||||
kdebug("Multi func device");
|
||||
// 这是一个多function的设备,因此查询剩余的function
|
||||
for (uint8_t func = 1; func < 8; ++func)
|
||||
{
|
||||
struct pci_device_structure_header_t *tmp_header;
|
||||
tmp_header = (struct pci_device_structure_header_t *)pci_read_header(&header_type, bus, device, func, false);
|
||||
|
||||
if (tmp_header->Vendor_ID != 0xffff)
|
||||
pci_checkFunction(bus, device, func);
|
||||
|
||||
// 释放内存
|
||||
kfree(tmp_header);
|
||||
}
|
||||
}
|
||||
|
||||
kfree(header);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void pci_checkBus(uint8_t bus)
|
||||
{
|
||||
for (uint8_t device = 0; device < 32; ++device)
|
||||
{
|
||||
pci_checkDevice(bus, device);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 扫描所有pci总线上的所有设备
|
||||
*
|
||||
*/
|
||||
void pci_checkAllBuses()
|
||||
{
|
||||
kinfo("Checking all devices in PCI bus...");
|
||||
int header_type;
|
||||
struct pci_device_structure_header_t *header = pci_read_header(&header_type, 0, 0, 0, false);
|
||||
|
||||
if (header_type == EINVAL)
|
||||
{
|
||||
kBUG("pci_checkAllBuses(): wrong header type!");
|
||||
// 此处内存已经在read header函数里面释放,不用重复释放
|
||||
return;
|
||||
}
|
||||
|
||||
header_type = header->HeaderType;
|
||||
|
||||
if ((header_type & 0x80) == 0) // Single pci host controller
|
||||
{
|
||||
pci_checkBus(0);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Multiple PCI host controller
|
||||
// 那么总线0,设备0,功能1则是总线1的pci主机控制器,以此类推
|
||||
struct pci_device_structure_header_t *tmp_header;
|
||||
for (uint8_t func = 0; func < 8; ++func)
|
||||
{
|
||||
tmp_header = (struct pci_device_structure_header_t *)pci_read_header(&header_type, 0, 0, func, false);
|
||||
|
||||
if (WARN_ON(header->Vendor_ID != 0xffff)) // @todo 这里的判断条件可能有点问题
|
||||
{
|
||||
kfree(tmp_header);
|
||||
break;
|
||||
}
|
||||
|
||||
pci_checkBus(func);
|
||||
|
||||
kfree(tmp_header);
|
||||
}
|
||||
}
|
||||
kfree(header);
|
||||
}
|
||||
|
||||
void pci_init()
|
||||
{
|
||||
kinfo("Initializing PCI bus...");
|
||||
pci_checkAllBuses();
|
||||
kinfo("Total pci device and function num = %d", count_device_list);
|
||||
|
||||
struct pci_device_structure_header_t *ptr = container_of(pci_device_structure_list, struct pci_device_structure_header_t, list);
|
||||
for (int i = 0; i < count_device_list; ++i)
|
||||
{
|
||||
if (ptr->HeaderType == 0x0)
|
||||
{
|
||||
if (ptr->Status & 0x10)
|
||||
{
|
||||
kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\tcap_pointer=%#010lx\tbar5=%#010lx, vendor=%#08x, device id=%#08x", i, ptr->Class_code, ptr->SubClass, ptr->Status, ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer, ((struct pci_device_structure_general_device_t *)ptr)->BAR5,
|
||||
ptr->Vendor_ID, ptr->Device_ID);
|
||||
uint32_t tmp = pci_read_config(ptr->bus, ptr->device, ptr->func, ((struct pci_device_structure_general_device_t *)ptr)->Capabilities_Pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\t", i, ptr->Class_code, ptr->SubClass, ptr->Status);
|
||||
}
|
||||
}
|
||||
else if (ptr->HeaderType == 0x1)
|
||||
{
|
||||
if (ptr->Status & 0x10)
|
||||
{
|
||||
kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\tcap_pointer=%#010lx", i, ptr->Class_code, ptr->SubClass, ptr->Status, ((struct pci_device_structure_pci_to_pci_bridge_t *)ptr)->Capability_Pointer);
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\t", i, ptr->Class_code, ptr->SubClass, ptr->Status);
|
||||
}
|
||||
}
|
||||
else if (ptr->HeaderType == 0x2)
|
||||
{
|
||||
kinfo("[ pci device %d ] class code = %d\tsubclass=%d\tstatus=%#010lx\t", i, ptr->Class_code, ptr->SubClass, ptr->Status);
|
||||
}
|
||||
|
||||
ptr = container_of(list_next(&(ptr->list)), struct pci_device_structure_header_t, list);
|
||||
}
|
||||
kinfo("PCI bus initialized.");
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @brief 获取 device structure
|
||||
*
|
||||
* @param class_code
|
||||
* @param sub_class
|
||||
* @param res 返回的结果数组
|
||||
*/
|
||||
void pci_get_device_structure(uint8_t class_code, uint8_t sub_class, struct pci_device_structure_header_t *res[], uint32_t *count_res)
|
||||
{
|
||||
|
||||
struct pci_device_structure_header_t *ptr = container_of(pci_device_structure_list, struct pci_device_structure_header_t, list);
|
||||
*count_res = 0;
|
||||
|
||||
for (int i = 0; i < count_device_list; ++i)
|
||||
{
|
||||
if ((ptr->Class_code == class_code) && (ptr->SubClass == sub_class))
|
||||
{
|
||||
kdebug("[%d] class_code=%d, sub_class=%d, progIF=%d, bar5=%#010lx", i, ptr->Class_code, ptr->SubClass, ptr->ProgIF, ((struct pci_device_structure_general_device_t *)ptr)->BAR5);
|
||||
|
||||
res[*count_res] = ptr;
|
||||
++(*count_res);
|
||||
}
|
||||
ptr = container_of(list_next(&(ptr->list)), struct pci_device_structure_header_t, list);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief 寻找符合指定类型的capability list
|
||||
*
|
||||
* @param pci_dev pci设备header
|
||||
* @param cap_type c要寻找的capability类型
|
||||
* @return uint64_t cap list的偏移量
|
||||
*/
|
||||
int32_t pci_enumerate_capability_list(struct pci_device_structure_header_t *pci_dev, uint32_t cap_type)
|
||||
{
|
||||
uint32_t cap_offset;
|
||||
switch (pci_dev->HeaderType)
|
||||
{
|
||||
case 0x00:
|
||||
|
||||
cap_offset = ((struct pci_device_structure_general_device_t *)pci_dev)->Capabilities_Pointer;
|
||||
break;
|
||||
|
||||
case 0x10:
|
||||
cap_offset = ((struct pci_device_structure_pci_to_pci_bridge_t *)pci_dev)->Capability_Pointer;
|
||||
break;
|
||||
default:
|
||||
// 不支持
|
||||
return -ENOSYS;
|
||||
}
|
||||
uint32_t tmp;
|
||||
while (1)
|
||||
{
|
||||
tmp = pci_read_config(pci_dev->bus, pci_dev->device, pci_dev->func, cap_offset);
|
||||
if ((tmp & 0xff) != cap_type)
|
||||
{
|
||||
if (((tmp & 0xff00) >> 8))
|
||||
{
|
||||
cap_offset = (tmp & 0xff00)>>8;
|
||||
continue;
|
||||
}
|
||||
else
|
||||
return -ENOSYS;
|
||||
}
|
||||
|
||||
return cap_offset;
|
||||
}
|
||||
}
|
@ -1,225 +0,0 @@
|
||||
#pragma once
|
||||
|
||||
#include <common/glib.h>
|
||||
#include <DragonOS/stdint.h>
|
||||
|
||||
#define PORT_PCI_CONFIG_ADDRESS 0xcf8
|
||||
#define PORT_PCI_CONFIG_DATA 0xcfc
|
||||
|
||||
// pci设备结构信息的链表
|
||||
struct List *pci_device_structure_list = NULL;
|
||||
|
||||
/**
|
||||
* @brief 初始化pci驱动
|
||||
*
|
||||
*/
|
||||
void pci_init();
|
||||
void rs_pci_init();
|
||||
// pci设备结构的通用标题字段
|
||||
struct pci_device_structure_header_t
|
||||
{
|
||||
struct List list;
|
||||
|
||||
// 包含msix table地址的bar的mmio基地址
|
||||
uint64_t msix_mmio_vaddr;
|
||||
uint64_t msix_mmio_size; // msix映射长度
|
||||
uint32_t msix_offset; // msix表的offset
|
||||
uint16_t msix_table_size; // msix表的表项数量
|
||||
|
||||
// ==== 以下三个变量表示该结构体所处的位置
|
||||
uint8_t bus;
|
||||
uint8_t device;
|
||||
uint8_t func;
|
||||
|
||||
uint16_t Vendor_ID; // 供应商ID 0xffff是一个无效值,在读取访问不存在的设备的配置空间寄存器时返回
|
||||
uint16_t Device_ID; // 设备ID,标志特定设备
|
||||
|
||||
uint16_t Command; // 提供对设备生成和响应pci周期的能力的控制 向该寄存器写入0时,设备与pci总线断开除配置空间访问以外的所有连接
|
||||
uint16_t Status; // 用于记录pci总线相关时间的状态信息寄存器
|
||||
|
||||
uint8_t RevisionID; // 修订ID,指定特定设备的修订标志符
|
||||
uint8_t ProgIF; // 编程接口字节,一个只读寄存器,指定设备具有的寄存器级别的编程接口(如果有的话)
|
||||
uint8_t SubClass; // 子类。指定设备执行的特定功能的只读寄存器
|
||||
uint8_t Class_code; // 类代码,一个只读寄存器,指定设备执行的功能类型
|
||||
|
||||
uint8_t CacheLineSize; // 缓存线大小:以 32 位为单位指定系统缓存线大小。设备可以限制它可以支持的缓存线大小的数量,如果不支持的值写入该字段,设备将表现得好像写入了 0 值
|
||||
uint8_t LatencyTimer; // 延迟计时器:以 PCI 总线时钟为单位指定延迟计时器。
|
||||
uint8_t HeaderType; // 标头类型 a value of 0x0 specifies a general device, a value of 0x1 specifies a PCI-to-PCI bridge, and a value of 0x2 specifies a CardBus bridge. If bit 7 of this register is set, the device has multiple functions; otherwise, it is a single function device.
|
||||
uint8_t BIST; // Represents that status and allows control of a devices BIST (built-in self test).
|
||||
// Here is the layout of the BIST register:
|
||||
// | bit7 | bit6 | Bits 5-4 | Bits 3-0 |
|
||||
// | BIST Capable | Start BIST | Reserved | Completion Code |
|
||||
// for more details, please visit https://wiki.osdev.org/PCI
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief 表头类型为0x0的pci设备结构
|
||||
*
|
||||
*/
|
||||
struct pci_device_structure_general_device_t
|
||||
{
|
||||
struct pci_device_structure_header_t header;
|
||||
uint32_t BAR0;
|
||||
uint32_t BAR1;
|
||||
uint32_t BAR2;
|
||||
uint32_t BAR3;
|
||||
uint32_t BAR4;
|
||||
uint32_t BAR5;
|
||||
uint32_t Cardbus_CIS_Pointer; // 指向卡信息结构,供在 CardBus 和 PCI 之间共享芯片的设备使用。
|
||||
|
||||
uint16_t Subsystem_Vendor_ID;
|
||||
uint16_t Subsystem_ID;
|
||||
|
||||
uint32_t Expansion_ROM_base_address;
|
||||
|
||||
uint8_t Capabilities_Pointer;
|
||||
uint8_t reserved0;
|
||||
uint16_t reserved1;
|
||||
|
||||
uint32_t reserved2;
|
||||
|
||||
uint8_t Interrupt_Line; // 指定设备的中断引脚连接到系统中断控制器的哪个输入,并由任何使用中断引脚的设备实现。对于 x86 架构,此寄存器对应于 PIC IRQ 编号 0-15(而不是 I/O APIC IRQ 编号),并且值0xFF定义为无连接。
|
||||
uint8_t Interrupt_PIN; // 指定设备使用的中断引脚。其中值为0x1INTA#、0x2INTB#、0x3INTC#、0x4INTD#,0x0表示设备不使用中断引脚。
|
||||
uint8_t Min_Grant; // 一个只读寄存器,用于指定设备所需的突发周期长度(以 1/4 微秒为单位)(假设时钟速率为 33 MHz)
|
||||
uint8_t Max_Latency; // 一个只读寄存器,指定设备需要多长时间访问一次 PCI 总线(以 1/4 微秒为单位)。
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* @brief 表头类型为0x1的pci设备结构(PCI to PCI Bridge)
|
||||
*
|
||||
*/
|
||||
struct pci_device_structure_pci_to_pci_bridge_t
|
||||
{
|
||||
struct pci_device_structure_header_t header;
|
||||
|
||||
uint32_t BAR0;
|
||||
uint32_t BAR1;
|
||||
|
||||
uint8_t Primary_Bus_Number;
|
||||
uint8_t Secondary_Bus_Number;
|
||||
uint8_t Subordinate_Bus_Number;
|
||||
uint8_t Secondary_Latency_Timer;
|
||||
|
||||
uint8_t io_base;
|
||||
uint8_t io_limit;
|
||||
uint16_t Secondary_Status;
|
||||
|
||||
uint16_t Memory_Base;
|
||||
uint16_t Memory_Limit;
|
||||
|
||||
uint16_t Prefetchable_Memory_Base;
|
||||
uint16_t Prefetchable_Memory_Limit;
|
||||
|
||||
uint32_t Prefetchable_Base_Upper_32_Bits;
|
||||
uint32_t Prefetchable_Limit_Upper_32_Bits;
|
||||
|
||||
uint16_t io_Base_Upper_16_Bits;
|
||||
uint16_t io_Limit_Upper_16_Bits;
|
||||
|
||||
uint8_t Capability_Pointer;
|
||||
uint8_t reserved0;
|
||||
uint16_t reserved1;
|
||||
|
||||
uint32_t Expansion_ROM_base_address;
|
||||
|
||||
uint8_t Interrupt_Line;
|
||||
uint8_t Interrupt_PIN;
|
||||
uint16_t Bridge_Control;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* @brief 表头类型为0x2的pci设备结构(PCI to CardBus Bridge)
|
||||
*
|
||||
*/
|
||||
struct pci_device_structure_pci_to_cardbus_bridge_t
|
||||
{
|
||||
struct pci_device_structure_header_t header;
|
||||
|
||||
uint32_t CardBus_Socket_ExCa_base_address;
|
||||
|
||||
uint8_t Offset_of_capabilities_list;
|
||||
uint8_t Reserved;
|
||||
uint16_t Secondary_status;
|
||||
|
||||
uint8_t PCI_bus_number;
|
||||
uint8_t CardBus_bus_number;
|
||||
uint8_t Subordinate_bus_number;
|
||||
uint8_t CardBus_latency_timer;
|
||||
|
||||
uint32_t Memory_Base_Address0;
|
||||
uint32_t Memory_Limit0;
|
||||
uint32_t Memory_Base_Address1;
|
||||
uint32_t Memory_Limit1;
|
||||
uint32_t IO_Base_Address0;
|
||||
uint32_t IO_Limit0;
|
||||
uint32_t IO_Base_Address1;
|
||||
uint32_t IO_Limit1;
|
||||
|
||||
uint8_t Interrupt_Line;
|
||||
uint8_t Interrupt_PIN;
|
||||
uint16_t Bridge_Control;
|
||||
|
||||
uint16_t Subsystem_Device_ID;
|
||||
uint16_t Subsystem_Vendor_ID;
|
||||
|
||||
uint32_t PC_Card_legacy_mode_base_address_16_bit;
|
||||
|
||||
} __attribute__((packed));
|
||||
|
||||
/**
|
||||
* @brief 从pci配置空间读取信息
|
||||
*
|
||||
* @param bus 总线号
|
||||
* @param slot 插槽号
|
||||
* @param func 功能号
|
||||
* @param offset 字节偏移量
|
||||
* @return uint 寄存器值
|
||||
*/
|
||||
uint32_t pci_read_config(uchar bus, uchar slot, uchar func, uchar offset);
|
||||
|
||||
/**
|
||||
* @brief 向pci配置空间写入信息
|
||||
*
|
||||
* @param bus 总线号
|
||||
* @param slot 设备号
|
||||
* @param func 功能号
|
||||
* @param offset 字节偏移量
|
||||
* @return uint 寄存器值
|
||||
*/
|
||||
uint pci_write_config(uchar bus, uchar slot, uchar func, uchar offset, uint32_t data);
|
||||
|
||||
/**
|
||||
* @brief 读取pci设备标头
|
||||
*
|
||||
* @param type 标头类型
|
||||
* @param bus 总线号
|
||||
* @param slot 插槽号
|
||||
* @param func 功能号
|
||||
* @return 返回的header的指针
|
||||
*/
|
||||
void *pci_read_header(int *type, uchar bus, uchar slot, uchar func, bool add_to_list);
|
||||
|
||||
/**
|
||||
* @brief 扫描所有pci总线上的所有设备
|
||||
*
|
||||
*/
|
||||
void pci_checkAllBuses();
|
||||
|
||||
/**
|
||||
* @brief 获取 device structure
|
||||
*
|
||||
* @param class_code
|
||||
* @param sub_class
|
||||
* @param res 返回的结果数组
|
||||
*/
|
||||
void pci_get_device_structure(uint8_t class_code, uint8_t sub_class, struct pci_device_structure_header_t *res[], uint32_t *count_res);
|
||||
|
||||
/**
|
||||
* @brief 寻找符合指定类型的capability list
|
||||
*
|
||||
* @param pci_dev pci设备header
|
||||
* @param cap_type c要寻找的capability类型
|
||||
* @return uint64_t cap list的偏移量
|
||||
*/
|
||||
int32_t pci_enumerate_capability_list(struct pci_device_structure_header_t *pci_dev, uint32_t cap_type);
|
@ -1,9 +1,9 @@
|
||||
use super::transport_pci::PciTransport;
|
||||
use super::virtio_impl::HalImpl;
|
||||
use crate::driver::net::virtio_net::virtio_net;
|
||||
use crate::driver::pci::pci::PciDeviceStructureGeneralDevice;
|
||||
use crate::driver::pci::pci::{
|
||||
get_pci_device_structure_mut, PciDeviceStructure, PCI_DEVICE_LINKEDLIST,
|
||||
get_pci_device_structure_mut, PciDeviceStructure, PciDeviceStructureGeneralDevice,
|
||||
PCI_DEVICE_LINKEDLIST,
|
||||
};
|
||||
use crate::libs::rwlock::RwLockWriteGuard;
|
||||
use crate::{kdebug, kerror, kwarn};
|
||||
|
@ -30,9 +30,7 @@
|
||||
#include <common/time.h>
|
||||
#include <common/unistd.h>
|
||||
#include <driver/disk/ahci/ahci.h>
|
||||
#include <driver/disk/ahci/ahci_rust.h>
|
||||
#include <driver/multiboot2/multiboot2.h>
|
||||
#include <driver/pci/pci.h>
|
||||
#include <driver/video/video.h>
|
||||
#include <driver/virtio/virtio.h>
|
||||
#include <exception/gate.h>
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "driver/keyboard/ps2_keyboard.h"
|
||||
#include "driver/mouse/ps2_mouse.h"
|
||||
#include "driver/multiboot2/multiboot2.h"
|
||||
#include "driver/pci/pci.h"
|
||||
#include <driver/timers/HPET/HPET.h>
|
||||
#include <driver/uart/uart.h>
|
||||
#include <driver/video/video.h>
|
||||
@ -165,8 +164,6 @@ void system_initialize()
|
||||
ps2_keyboard_init();
|
||||
io_mfence();
|
||||
|
||||
pci_init();
|
||||
|
||||
rs_pci_init();
|
||||
|
||||
// 这里必须加内存屏障,否则会出错
|
||||
|
@ -81,8 +81,7 @@ impl Syscall {
|
||||
timezone: *mut PosixTimeZone,
|
||||
) -> Result<usize, SystemError> {
|
||||
// TODO; 处理时区信息
|
||||
// kdebug!("enter sys_do_gettimeofday");
|
||||
if tv == null_mut() {
|
||||
if tv.is_null() {
|
||||
return Err(SystemError::EFAULT);
|
||||
}
|
||||
let mut tv_buf =
|
||||
|
@ -142,7 +142,9 @@ impl Timekeeper {
|
||||
}
|
||||
}
|
||||
pub fn timekeeper() -> &'static Timekeeper {
|
||||
return unsafe { __TIMEKEEPER.as_ref().unwrap() };
|
||||
let r = unsafe { __TIMEKEEPER.as_ref().unwrap() };
|
||||
|
||||
return r;
|
||||
}
|
||||
|
||||
pub fn timekeeper_init() {
|
||||
|
Reference in New Issue
Block a user