feat(panic): FUCK [panic] mode=strict|fallback + realtest image variant
- UTSM panic_full returns in fallback mode (logs [PANIC:FALLBACK] + code + hit count); panic_halt keeps always-halt sites (CPU exception, VMM-E11 LA57, VMM-E15 DSK jump, UTSM-E42 test hook). Call sites given safe continuations. - Mode passed to DSK/FirstInit/login/desktop via DSK_BOOT_FLAG_PANIC_FALLBACK; DKM kernel_api.panic / kern.log.panic return to driver; ext4 fatal aborts the op via setjmp/longjmp and DSK falls back to FAT32 ESP. - build.ps1/Makefile: dev=strict, release=fallback, new realtest (release options + strict); default -Variant all; serialized iso packing under -j. - Fix '*/' inside comments (dkm.h, kernel_api.h, bus.c) that broke the build. - Includes pending work: dkm_bus service bus, mt7920/wlan drivers, desktop files/startmenu/prank, pe-tools, diskinfo, docs. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -26,6 +26,26 @@ struct dkm_log_api {
|
||||
void (*panic)(const char *msg);
|
||||
};
|
||||
|
||||
/* D6 万物互联:dkm_bus 镜像(布局对齐 UTSM include/utsm/dkm.h) */
|
||||
struct dkm_bus_service {
|
||||
char name[48];
|
||||
u32 version;
|
||||
u32 flags;
|
||||
void *fn;
|
||||
const void *provider;
|
||||
};
|
||||
|
||||
struct dkm_bus_api {
|
||||
u32 magic;
|
||||
u32 version;
|
||||
int (*register_service)(const char *name, u32 version, void *fn);
|
||||
int (*unregister_service)(const char *name);
|
||||
int (*lookup)(const char *name, void **out_fn, u32 *out_version);
|
||||
int (*probe)(const char *name, void **out_fn, u32 *out_version);
|
||||
u32 (*count)(void);
|
||||
const struct dkm_bus_service *(*at)(u32 index);
|
||||
};
|
||||
|
||||
struct dkm_kernel_api {
|
||||
u32 version;
|
||||
u32 size;
|
||||
@@ -47,6 +67,19 @@ struct dkm_kernel_api {
|
||||
u64 fb_pitch;
|
||||
u16 fb_bpp;
|
||||
const void *boot_modules_response;
|
||||
/* —— 尾部追加字段镜像(DKM_ABI v1;到 bus 为止) —— */
|
||||
void *irq_register; /* int (*)(u8, void*) */
|
||||
u64 hhdm_offset;
|
||||
const void *block;
|
||||
const void *mmio;
|
||||
void *mm_map_mmio;
|
||||
void *mm_unmap_mmio;
|
||||
void *register_apic_eoi;
|
||||
void *irq_vector_alloc;
|
||||
void *irq_vector_free;
|
||||
const void *sched;
|
||||
const void *kapi;
|
||||
const struct dkm_bus_api *bus;
|
||||
};
|
||||
|
||||
struct dkm_driver_handle;
|
||||
@@ -185,6 +218,31 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
devfs_file("fb0", info);
|
||||
}
|
||||
|
||||
/* /dev/services — D6 万物互联:总线已注册服务清单 */
|
||||
if (api->bus && api->bus->magic == 0x53425553u /* "SBUS" */) {
|
||||
char cnt[24];
|
||||
cnt[0] = '0'; cnt[1] = 'x';
|
||||
u64 v = api->bus->count();
|
||||
u32 p = 2;
|
||||
if (v == 0) cnt[p++] = '0';
|
||||
else {
|
||||
char r[18]; u32 q = 0;
|
||||
while (v) { r[q++] = "0123456789abcdef"[v&0xf]; v>>=4; }
|
||||
while (q) cnt[p++] = r[--q];
|
||||
}
|
||||
cnt[p] = 0;
|
||||
devfs_file("services", cnt);
|
||||
|
||||
g_log->info("[devfs] /dev/services/");
|
||||
for (u32 i = 0; i < api->bus->count(); i++) {
|
||||
const struct dkm_bus_service *s = api->bus->at(i);
|
||||
if (s && s->name[0]) {
|
||||
g_log->info("[devfs] ");
|
||||
g_log->info(s->name);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* /dev/modules — count from boot_modules */
|
||||
const struct limine_module_response *rsp =
|
||||
(const struct limine_module_response *)api->boot_modules_response;
|
||||
|
||||
@@ -741,6 +741,9 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
(mac[0] & 1)) {
|
||||
raw_log("[e1000] MAC read failed (zero/multicast)\n");
|
||||
g_log->panic("E1K-E01 MAC READ FAILED");
|
||||
/* fallback:本地管理单播地址(bit1=LAA,bit0=0),"DESHB" */
|
||||
mac[0]=0x02; mac[1]=0x44; mac[2]=0x45; mac[3]=0x53; mac[4]=0x48; mac[5]=0x42;
|
||||
raw_log("[e1000] fallback: using locally administered MAC\n");
|
||||
}
|
||||
|
||||
raw_mac("[e1000] MAC=", mac);
|
||||
|
||||
@@ -1098,10 +1098,12 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
dkm_delay_ms(20);
|
||||
}
|
||||
}
|
||||
dkm_delay_ms(100); /* 端口稳定 */
|
||||
dkm_delay_ms(1500); /* 控制器复位后 U 盘重新连接 */
|
||||
|
||||
/* 扫描端口,枚举 MSC */
|
||||
/* 扫描端口,枚举 MSC。第一遍没有就再等一次。 */
|
||||
g_msc.ready = 0;
|
||||
for (int pass = 0; pass < 2 && !g_msc.ready; pass++) {
|
||||
if (pass == 1) dkm_delay_ms(1500);
|
||||
for (u32 p = 0; p < g_nports; p++) {
|
||||
u32 po = g_caplen + EHCI_OP_PORTSC + p * EHCI_PORT_STRIDE;
|
||||
u32 ps = mmio_read32(po);
|
||||
@@ -1138,6 +1140,7 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
log_hex("[ehci] MSC device block_size=", blk);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* 注册 block provider */
|
||||
if (g_msc.ready && api->block && api->block->register_device) {
|
||||
|
||||
@@ -0,0 +1,721 @@
|
||||
/* DKM mt7920 — MediaTek MT7920 / Wi-Fi 6 (PCI 14c3:7920), ConnAC2 PCIe
|
||||
*
|
||||
* 本机无线网卡。驱动分阶段落地,当前阶段 = MCU 固件下载(patch + RAM),
|
||||
* 到 "N9 firmware ready" 为止。扫描/关联仍为显式 panic(MT7920-E10/E11),
|
||||
* 不伪装成功。
|
||||
*
|
||||
* 固件通过 Limine boot module 送入(limine.conf fw:mt7920_patch / fw:mt7920_ram),
|
||||
* 驱动用 boot_modules_response 按 cmdline 定位,不嵌进 .drv。
|
||||
*
|
||||
* 寄存器/流程对拍 Linux mt76(drivers/net/wireless/mediatek/mt76),
|
||||
* 版本见 .build_tmp/mt76ref。全程串口日志,便于实机逐步 bring-up。
|
||||
*
|
||||
* 这是硬件 bring-up 第一阶段:本环境(QEMU 无此卡)无法验证,需实机串口迭代。
|
||||
*/
|
||||
|
||||
#include "../dkm_shared.h"
|
||||
#include "../dkm_instr.h"
|
||||
|
||||
/* ---- limine boot module 结构(与 bootfs.drv 一致) ---- */
|
||||
struct limine_file {
|
||||
u64 revision;
|
||||
void *address;
|
||||
u64 size;
|
||||
char *path;
|
||||
char *cmdline;
|
||||
u32 media_type;
|
||||
u32 unused;
|
||||
u32 tftp_ip;
|
||||
u32 tftp_port;
|
||||
u32 partition_index;
|
||||
u32 mbr_disk_id;
|
||||
u8 gpt_disk_uuid[16];
|
||||
u8 gpt_part_uuid[16];
|
||||
u8 part_uuid[16];
|
||||
};
|
||||
struct limine_module_response {
|
||||
u64 revision;
|
||||
u64 module_count;
|
||||
struct limine_file **modules;
|
||||
};
|
||||
|
||||
static const char *const g_depends[] = {"pci"};
|
||||
static const char *const g_provides[] = {"netdev"};
|
||||
__attribute__((visibility("default"), used))
|
||||
const struct dkm_driver_desc driver_desc = {
|
||||
.magic=DKM_DRIVER_MAGIC,.abi_version=DKM_ABI_VERSION,
|
||||
.desc_size=sizeof(struct dkm_driver_desc),
|
||||
.name="mt7920",.version="0.2.0",.vendor="Deshab",
|
||||
.driver_class=9,.stage=3,.flags=0,.priority=0,
|
||||
.depends=g_depends,.depends_count=1,
|
||||
.provides=g_provides,.provides_count=1,.min_kernel_abi=1,
|
||||
};
|
||||
|
||||
#define MT_VID 0x14C3u
|
||||
#define MT_DID 0x7920u
|
||||
|
||||
/* ===== 寄存器(对拍 mt792x_regs.h / mt7921/regs.h,物理地址) ===== */
|
||||
#define MT_HW_CHIPID 0x70010200u
|
||||
#define MT_HW_REV 0x70010204u
|
||||
#define MT_HW_BOUND 0x70010020u
|
||||
#define MT_TOP_LPCR_HOST_BAND0 0x18060010u
|
||||
#define MT_TOP_LPCR_HOST_FW_OWN (1u<<0)
|
||||
#define MT_TOP_LPCR_HOST_DRV_OWN (1u<<1)
|
||||
#define MT_WFSYS_RST 0x18000140u
|
||||
#define WFSYS_SW_RST_B (1u<<0)
|
||||
#define WFSYS_SW_INIT_DONE (1u<<4)
|
||||
|
||||
/* conn_host_csr_top 0x7c060000 → BAR0 0xe0000 */
|
||||
#define MT_CONN_ON_LPCTL 0x0e0010u
|
||||
#define PCIE_LPCR_HOST_SET_OWN (1u<<0)
|
||||
#define PCIE_LPCR_HOST_CLR_OWN (1u<<1)
|
||||
#define PCIE_LPCR_HOST_OWN_SYNC (1u<<2)
|
||||
#define MT_CONN_ON_MISC 0x0e00f0u
|
||||
#define MT_TOP_MISC_FW_STATE 0x7u /* GENMASK(2,0) */
|
||||
#define MT_TOP_MISC2_FW_PWR_ON (1u<<0)
|
||||
#define MT_TOP_MISC2_FW_N9_RDY 0x3u /* GENMASK(1,0) */
|
||||
|
||||
/* WFDMA0 直接 BAR0 偏移(base 0xd4000) */
|
||||
#define MT_WFDMA0(ofs) (0xd4000u + (ofs))
|
||||
#define MT_WFDMA0_RST MT_WFDMA0(0x100)
|
||||
#define MT_WFDMA0_RST_LOGIC_RST (1u<<4)
|
||||
#define MT_WFDMA0_RST_DMASHDL_ALL_RST (1u<<5)
|
||||
#define MT_MCU_CMD MT_WFDMA0(0x1f0)
|
||||
#define MT_WFDMA0_GLO_CFG MT_WFDMA0(0x208)
|
||||
#define MT_WFDMA0_GLO_CFG_TX_DMA_EN (1u<<0)
|
||||
#define MT_WFDMA0_GLO_CFG_TX_DMA_BUSY (1u<<1)
|
||||
#define MT_WFDMA0_GLO_CFG_RX_DMA_EN (1u<<2)
|
||||
#define MT_WFDMA0_GLO_CFG_RX_DMA_BUSY (1u<<3)
|
||||
#define MT_WFDMA0_GLO_CFG_TX_WB_DDONE (1u<<6)
|
||||
#define MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN (1u<<12)
|
||||
#define MT_WFDMA0_GLO_CFG_RX_WB_DDONE (1u<<13)
|
||||
#define MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN (1u<<15)
|
||||
#define MT_WFDMA0_GLO_CFG_OMIT_TX_INFO (1u<<28)
|
||||
#define MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2 (1u<<21)
|
||||
#define MT_WFDMA0_GLO_CFG_CLK_GAT_DIS (1u<<30)
|
||||
#define MT_WFDMA0_GLO_CFG_DMA_SIZE_SHIFT 4
|
||||
#define MT_WFDMA0_RST_DTX_PTR MT_WFDMA0(0x20c)
|
||||
#define MT_WFDMA0_PRI_DLY_INT_CFG0 MT_WFDMA0(0x2f0)
|
||||
#define MT_WFDMA0_GLO_CFG_EXT0 MT_WFDMA0(0x2b0)
|
||||
#define MT_WFDMA0_GLO_CFG_EXT0_CSR_TX_DMASHDL_EN (1u<<6)
|
||||
#define MT_DMASHDL_SW_CONTROL (0x7c026004u) /* via fixed map below */
|
||||
#define MT_DMASHDL_DMASHDL_BYPASS (1u<<28)
|
||||
#define MT_WFDMA0_HOST_INT_ENA MT_WFDMA0(0x204)
|
||||
#define MT_WFDMA0_HOST_INT_STA MT_WFDMA0(0x200)
|
||||
#define MT_MCU2HOST_SW_INT_ENA MT_WFDMA0(0x1f4)
|
||||
#define MT_WFDMA_DUMMY_CR (0x54000120u)
|
||||
#define MT_WFDMA_NEED_REINIT (1u<<1)
|
||||
|
||||
#define MT_TX_RING_BASE MT_WFDMA0(0x300)
|
||||
#define MT_RX_EVENT_RING_BASE MT_WFDMA0(0x500)
|
||||
#define MT_RX_DATA_RING_BASE MT_WFDMA0(0x520)
|
||||
#define MT_WFDMA0_TX_RING0_EXT_CTRL MT_WFDMA0(0x600)
|
||||
#define MT_RING_SIZE 0x10u
|
||||
|
||||
#define MT_PCIE_MAC_INT_ENABLE 0x010188u /* PCIE_MAC_IREG 0x74030000→0x10000 +0x188 */
|
||||
|
||||
/* L1 remap(高位地址窗口),MT_INFRA 0xfe000 */
|
||||
#define MT_HIF_REMAP_L1 0x0fe24cu
|
||||
#define MT_HIF_REMAP_BASE_L1 0x40000u
|
||||
|
||||
/* ConnAC2 队列索引 */
|
||||
#define TXQ_FWDL 16
|
||||
#define TXQ_MCU_WM 17
|
||||
#define RXQ_MCU_WM 0
|
||||
|
||||
/* MCU 命令 */
|
||||
#define MCU_CMD_TARGET_ADDRESS_LEN_REQ 0x01
|
||||
#define MCU_CMD_FW_START_REQ 0x02
|
||||
#define MCU_CMD_NIC_POWER_CTRL 0x04
|
||||
#define MCU_CMD_PATCH_START_REQ 0x05
|
||||
#define MCU_CMD_PATCH_FINISH_REQ 0x07
|
||||
#define MCU_CMD_PATCH_SEM_CONTROL 0x10
|
||||
#define MCU_CMD_FW_SCATTER 0xee
|
||||
|
||||
#define PATCH_SEM_RELEASE 0
|
||||
#define PATCH_SEM_GET 1
|
||||
#define PATCH_NOT_DL_SEM_SUCCESS 2
|
||||
#define PATCH_IS_DL 3
|
||||
#define PATCH_REL_SEM_SUCCESS 4
|
||||
|
||||
#define DL_MODE_NEED_RSP (1u<<31)
|
||||
#define FW_START_OVERRIDE (1u<<0)
|
||||
#define FW_FEATURE_OVERRIDE_ADDR (1u<<5)
|
||||
#define FW_FEATURE_NON_DL (1u<<6)
|
||||
#define PATCH_SEC_TYPE_MASK 0xffffu
|
||||
#define PATCH_SEC_TYPE_INFO 0x2
|
||||
|
||||
#define MCU_PKT_ID 0xa0u
|
||||
#define FWDL_MAX_LEN 4096
|
||||
|
||||
/* ===== 固件头结构(big-endian patch header,little-endian ram trailer) ===== */
|
||||
struct patch_hdr {
|
||||
char build_date[16];
|
||||
char platform[4];
|
||||
u32 hw_sw_ver; /* BE */
|
||||
u32 patch_ver; /* BE */
|
||||
u16 checksum;
|
||||
u16 rsv;
|
||||
struct {
|
||||
u32 patch_ver;
|
||||
u32 subsys;
|
||||
u32 feature;
|
||||
u32 n_region; /* BE */
|
||||
u32 crc;
|
||||
u32 rsv[11];
|
||||
} desc;
|
||||
};
|
||||
struct patch_sec {
|
||||
u32 type; /* BE */
|
||||
u32 offs; /* BE */
|
||||
u32 size; /* BE */
|
||||
u32 addr; /* BE (info.addr) */
|
||||
u32 len; /* BE (info.len) */
|
||||
u32 sec_key_idx;
|
||||
u32 align_len;
|
||||
u32 rsv[9];
|
||||
};
|
||||
struct fw_trailer {
|
||||
u8 chip_id;
|
||||
u8 eco_code;
|
||||
u8 n_region;
|
||||
u8 format_ver;
|
||||
u8 format_flag;
|
||||
u8 rsv[2];
|
||||
char fw_ver[10];
|
||||
char build_date[15];
|
||||
u32 crc;
|
||||
};
|
||||
struct fw_region {
|
||||
u32 decomp_crc;
|
||||
u32 decomp_len;
|
||||
u32 decomp_blk_sz;
|
||||
u8 rsv[4];
|
||||
u32 addr; /* LE */
|
||||
u32 len; /* LE */
|
||||
u8 feature_set;
|
||||
u8 type;
|
||||
u8 rsv1[14];
|
||||
};
|
||||
|
||||
/* mt76 descriptor */
|
||||
struct mt_desc { u32 buf0; u32 ctrl; u32 buf1; u32 info; };
|
||||
#define MT_DMA_CTL_SD_LEN0_SHIFT 16
|
||||
#define MT_DMA_CTL_LAST_SEC0 (1u<<30)
|
||||
#define MT_DMA_CTL_DMA_DONE (1u<<31)
|
||||
|
||||
/* ===== 驱动状态 ===== */
|
||||
static struct dkm_log_api *g_log;
|
||||
static const struct dkm_kernel_api *g_api;
|
||||
static volatile u8 *g_bar; /* BAR0 虚拟基址 */
|
||||
static u8 g_bus, g_dev, g_func;
|
||||
static u8 g_mcu_seq;
|
||||
|
||||
struct mt_queue {
|
||||
struct mt_desc *desc; /* 虚拟 */
|
||||
u64 desc_phys;
|
||||
u32 ndesc;
|
||||
u32 head;
|
||||
u32 ring_base; /* 寄存器基 */
|
||||
u32 hw_idx; /* ring index within base */
|
||||
};
|
||||
static struct mt_queue g_q_fwdl, g_q_wm, g_q_rxmcu;
|
||||
static struct dkm_dma_buffer g_tx_scratch; /* TX 命令/scatter 暂存 */
|
||||
static struct dkm_dma_buffer g_rx_bufs; /* RX buffer 池 */
|
||||
#define RX_NDESC 8u
|
||||
#define TX_SCRATCH_SZ 8192u
|
||||
|
||||
/* ===== 串口日志 ===== */
|
||||
#define COM1 0x3F8
|
||||
static void rlog(const char *s){ while(*s){char c=*s++; if(c=='\n'){dkm_serial_wait_tx(COM1);dkm_outb(COM1,'\r');} dkm_serial_wait_tx(COM1);dkm_outb(COM1,(u8)c);} }
|
||||
static void rhex(const char *p, u64 v){ static const char hx[]="0123456789abcdef"; char b[19]; rlog(p); b[0]='0';b[1]='x'; for(int i=0;i<16;i++)b[2+i]=hx[(v>>((15-i)*4))&0xf]; b[18]=0; rlog(b); rlog("\n"); }
|
||||
|
||||
/* strict 模式 g_log->panic 不返回;fallback 模式返回,调用点随后 return -1 */
|
||||
static void mt_panic(const char *sym){ if(g_log)g_log->panic(sym); else for(;;)__asm__ volatile("cli;hlt"); }
|
||||
|
||||
/* ===== 基础 MMIO ===== */
|
||||
static inline u32 bar_rr(u32 off){ return *(volatile u32*)(g_bar+off); }
|
||||
static inline void bar_wr(u32 off,u32 v){ *(volatile u32*)(g_bar+off)=v; }
|
||||
static inline void bar_set(u32 off,u32 m){ bar_wr(off, bar_rr(off)|m); }
|
||||
static inline void bar_clr(u32 off,u32 m){ bar_wr(off, bar_rr(off)&~m); }
|
||||
|
||||
/* 固定映射:把高位物理地址翻成 BAR0 偏移(对拍 __mt7921_reg_addr 子集) */
|
||||
static u32 fixed_map(u32 addr){
|
||||
struct { u32 phys, maps, size; } m[] = {
|
||||
{0x54000000,0x02000,0x01000},
|
||||
{0x55000000,0x03000,0x01000},
|
||||
{0x7c000000,0xf0000,0x10000},
|
||||
{0x7c020000,0xd0000,0x10000},
|
||||
{0x7c060000,0xe0000,0x10000},
|
||||
{0x74030000,0x10000,0x10000},
|
||||
};
|
||||
if(addr<0x100000) return addr;
|
||||
for(u32 i=0;i<sizeof(m)/sizeof(m[0]);i++){
|
||||
if(addr<m[i].phys) continue;
|
||||
u32 ofs=addr-m[i].phys;
|
||||
if(ofs>m[i].size) continue;
|
||||
return m[i].maps+ofs;
|
||||
}
|
||||
return 0; /* 需 L1 remap */
|
||||
}
|
||||
|
||||
/* L1 remap 访问高位寄存器(0x18xxxxxx / 0x70xxxxxx 等) */
|
||||
static u32 l1_addr(u32 addr){
|
||||
u32 base=addr>>16, offset=addr&0xffff;
|
||||
u32 cur=bar_rr(MT_HIF_REMAP_L1);
|
||||
bar_wr(MT_HIF_REMAP_L1,(cur&~0xffffu)|(base&0xffffu));
|
||||
(void)bar_rr(MT_HIF_REMAP_L1);
|
||||
return MT_HIF_REMAP_BASE_L1+offset;
|
||||
}
|
||||
static u32 reg_rr(u32 phys){ u32 o=fixed_map(phys); if(!o)o=l1_addr(phys); return bar_rr(o); }
|
||||
static void reg_wr(u32 phys,u32 v){ u32 o=fixed_map(phys); if(!o)o=l1_addr(phys); bar_wr(o,v); }
|
||||
static void reg_set(u32 phys,u32 m){ reg_wr(phys,reg_rr(phys)|m); }
|
||||
static void reg_clr(u32 phys,u32 m){ reg_wr(phys,reg_rr(phys)&~m); }
|
||||
|
||||
static int poll_reg(u32 phys,u32 mask,u32 val,u32 ms){
|
||||
u64 dl=dkm_rdtsc()+dkm_tsc_per_ms*(u64)ms;
|
||||
do { if((reg_rr(phys)&mask)==val) return 0; __asm__ volatile("pause"); } while(dkm_rdtsc()<dl);
|
||||
return (reg_rr(phys)&mask)==val?0:-1;
|
||||
}
|
||||
static int poll_bar(u32 off,u32 mask,u32 val,u32 ms){
|
||||
u64 dl=dkm_rdtsc()+dkm_tsc_per_ms*(u64)ms;
|
||||
do { if((bar_rr(off)&mask)==val) return 0; __asm__ volatile("pause"); } while(dkm_rdtsc()<dl);
|
||||
return (bar_rr(off)&mask)==val?0:-1;
|
||||
}
|
||||
|
||||
/* ===== PCI ===== */
|
||||
#define PCI_ADDR_PORT 0xCF8u
|
||||
#define PCI_DATA_PORT 0xCFCu
|
||||
static inline void outl_(u16 p,u32 v){__asm__ volatile("outl %0,%1"::"a"(v),"Nd"(p));}
|
||||
static inline u32 inl_(u16 p){u32 v;__asm__ volatile("inl %1,%0":"=a"(v):"Nd"(p));return v;}
|
||||
static u32 pci_rd(u8 b,u8 d,u8 f,u8 r){ outl_(PCI_ADDR_PORT,(1u<<31)|((u32)b<<16)|((u32)d<<11)|((u32)f<<8)|(r&0xFC)); return inl_(PCI_DATA_PORT); }
|
||||
static void pci_wr(u8 b,u8 d,u8 f,u8 r,u32 v){ outl_(PCI_ADDR_PORT,(1u<<31)|((u32)b<<16)|((u32)d<<11)|((u32)f<<8)|(r&0xFC)); outl_(PCI_DATA_PORT,v); }
|
||||
|
||||
static int mt_find(void){
|
||||
for(u32 b=0;b<256;b++) for(u8 d=0;d<32;d++){
|
||||
u32 vd=pci_rd((u8)b,d,0,0);
|
||||
if((vd&0xffff)==0xffff) continue;
|
||||
if((u16)(vd&0xffff)==MT_VID && (u16)(vd>>16)==MT_DID){ g_bus=(u8)b; g_dev=d; g_func=0; return 0; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* ===== boot module 固件定位 ===== */
|
||||
static int fw_find(const char *tag, const u8 **data, u64 *size){
|
||||
const struct limine_module_response *rsp=(const struct limine_module_response*)g_api->boot_modules_response;
|
||||
if(!rsp) return -1;
|
||||
for(u64 i=0;i<rsp->module_count;i++){
|
||||
struct limine_file *f=rsp->modules[i];
|
||||
if(!f||!f->cmdline) continue;
|
||||
const char *a=f->cmdline,*b=tag;
|
||||
while(*a&&*a==*b){a++;b++;}
|
||||
if(*a==0&&*b==0){ *data=(const u8*)f->address; *size=f->size; return 0; }
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
||||
static u32 be32(const u8 *p){ return ((u32)p[0]<<24)|((u32)p[1]<<16)|((u32)p[2]<<8)|p[3]; }
|
||||
static u32 le32(const u8 *p){ return ((u32)p[3]<<24)|((u32)p[2]<<16)|((u32)p[1]<<8)|p[0]; }
|
||||
static void memcpy_(void *d,const void *s,u64 n){ u8 *dd=d; const u8 *ss=s; while(n--)*dd++=*ss++; }
|
||||
static void memset_(void *d,u8 v,u64 n){ u8 *dd=d; while(n--)*dd++=v; }
|
||||
|
||||
/* ===== DMA 队列 ===== */
|
||||
static int q_alloc(struct mt_queue *q,u32 ndesc,u32 ring_base,u32 hw_idx){
|
||||
struct dkm_dma_buffer buf;
|
||||
u64 bytes=(u64)ndesc*sizeof(struct mt_desc);
|
||||
u64 pages=(bytes+4095)/4096;
|
||||
if(g_api->dma->alloc_pages(pages,4096,0xFFFFFFFFull,&buf)!=0) return -1;
|
||||
memset_(buf.virt,0,pages*4096);
|
||||
q->desc=(struct mt_desc*)buf.virt;
|
||||
q->desc_phys=buf.phys;
|
||||
q->ndesc=ndesc;
|
||||
q->head=0;
|
||||
q->ring_base=ring_base;
|
||||
q->hw_idx=hw_idx;
|
||||
return 0;
|
||||
}
|
||||
/* 把队列的 desc_base/ring_size 写入硬件 ring 寄存器,并清 cpu/dma idx */
|
||||
static void q_sync(struct mt_queue *q){
|
||||
u32 r=q->ring_base+q->hw_idx*MT_RING_SIZE;
|
||||
bar_wr(r+0x00,(u32)q->desc_phys); /* desc_base */
|
||||
bar_wr(r+0x04,q->ndesc); /* ring_size */
|
||||
bar_wr(r+0x08,0); /* cpu_idx */
|
||||
bar_wr(r+0x0c,0); /* dma_idx (hw) */
|
||||
q->head=0;
|
||||
}
|
||||
static void q_kick(struct mt_queue *q){
|
||||
__asm__ volatile("sfence":::"memory");
|
||||
bar_wr(q->ring_base+q->hw_idx*MT_RING_SIZE+0x08,q->head);
|
||||
}
|
||||
|
||||
/* 把一段数据丢进 TX 队列(单段),info=0 */
|
||||
static int tx_raw(struct mt_queue *q,u64 phys,u32 len){
|
||||
u32 idx=q->head;
|
||||
if((q->head+1)%q->ndesc==0 && q->ndesc<=1) return -1;
|
||||
struct mt_desc *d=&q->desc[idx];
|
||||
u32 ctrl=((len&0x3fff)<<MT_DMA_CTL_SD_LEN0_SHIFT)|MT_DMA_CTL_LAST_SEC0;
|
||||
d->buf0=(u32)phys;
|
||||
d->buf1=0;
|
||||
d->info=0;
|
||||
__asm__ volatile("sfence":::"memory");
|
||||
d->ctrl=ctrl;
|
||||
q->head=(q->head+1)%q->ndesc;
|
||||
q_kick(q);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* 等待 RX MCU ring 出现一个响应,拷到 out(最多 cap),返回长度;超时 -1 */
|
||||
static int rx_wait(u8 *out,u32 cap,u32 ms){
|
||||
u32 r=g_q_rxmcu.ring_base+g_q_rxmcu.hw_idx*MT_RING_SIZE;
|
||||
u64 dl=dkm_rdtsc()+dkm_tsc_per_ms*(u64)ms;
|
||||
u32 tail=g_q_rxmcu.head;
|
||||
do {
|
||||
u32 dma_idx=bar_rr(r+0x0c);
|
||||
if(dma_idx!=tail){
|
||||
struct mt_desc *d=&g_q_rxmcu.desc[tail];
|
||||
u32 ctrl=d->ctrl;
|
||||
u32 len=(ctrl>>MT_DMA_CTL_SD_LEN0_SHIFT)&0x3fff;
|
||||
const u8 *src=(const u8*)(g_api->hhdm_offset + d->buf0);
|
||||
u32 n=len<cap?len:cap;
|
||||
memcpy_(out,src,n);
|
||||
/* 回收:重新武装该 desc(重填 buffer 长度) */
|
||||
d->ctrl=((2048u&0x3fff)<<MT_DMA_CTL_SD_LEN0_SHIFT);
|
||||
tail=(tail+1)%g_q_rxmcu.ndesc;
|
||||
g_q_rxmcu.head=tail;
|
||||
bar_wr(r+0x08,tail); /* cpu_idx 前进,归还 buffer */
|
||||
return (int)n;
|
||||
}
|
||||
__asm__ volatile("pause");
|
||||
} while(dkm_rdtsc()<dl);
|
||||
return -1;
|
||||
}
|
||||
|
||||
/* 发一条标准 MCU 命令(带 64 字节 txd 头),payload 在 g_tx_scratch 之后;
|
||||
* wait=1 时等响应并返回首字节(PATCH_SEM / PATCH_FINISH 用)。 */
|
||||
static int mcu_send(int cmd_id,int ext_id,const void *payload,u32 plen,int wait,u8 *rbyte){
|
||||
u8 *buf=(u8*)g_tx_scratch.virt;
|
||||
u32 hdr=64;
|
||||
memset_(buf,0,hdr);
|
||||
u32 total=hdr+plen;
|
||||
if(total>TX_SCRATCH_SZ) return -2;
|
||||
memcpy_(buf+hdr,payload,plen);
|
||||
|
||||
u8 seq=++g_mcu_seq & 0xf; if(!seq) seq=++g_mcu_seq & 0xf;
|
||||
u32 *txd=(u32*)buf;
|
||||
/* txd[0]: TX_BYTES(total) | PKT_FMT(CMD=2)<<23 | Q_IDX(0x20)<<25 */
|
||||
txd[0]=(total&0xffff)|(2u<<23)|(0x20u<<25);
|
||||
/* txd[1]: LONG_FORMAT bit31 | HDR_FORMAT(CMD=1)<<16 */
|
||||
txd[1]=(1u<<31)|(1u<<16);
|
||||
/* mcu_txd 覆盖在 offset 32 */
|
||||
u8 *m=buf+32;
|
||||
u16 mlen=(u16)(total-32);
|
||||
m[0]=(u8)(mlen&0xff); m[1]=(u8)(mlen>>8); /* len */
|
||||
u16 pq=(u16)((1u<<15)|(0x20u<<10));
|
||||
m[2]=(u8)(pq&0xff); m[3]=(u8)(pq>>8); /* pq_id */
|
||||
m[4]=(u8)cmd_id; /* cid */
|
||||
m[5]=MCU_PKT_ID; /* pkt_type */
|
||||
m[6]=ext_id?2:0; /* set_query: SET=2 for ext */
|
||||
m[7]=seq; /* seq */
|
||||
m[9]=(u8)ext_id; /* ext_cid */
|
||||
m[10]=0; /* s2d_index=H2N */
|
||||
m[11]=ext_id?1:0; /* ext_cid_ack */
|
||||
|
||||
if(tx_raw(&g_q_wm,g_tx_scratch.phys,total)!=0) return -3;
|
||||
|
||||
if(!wait) { dkm_delay_ms(2); return 0; }
|
||||
static u8 rbuf[2048];
|
||||
int n=rx_wait(rbuf,sizeof(rbuf),1000);
|
||||
if(n<0) return -4;
|
||||
/* rxd 头 36 字节;seq 在 offset 33(rxd[6]=24, len+pkt=4 →28, eid=28,seq=29) */
|
||||
if(n>=34){
|
||||
u8 rseq=rbuf[29];
|
||||
if(rseq!=seq) { /* 不匹配也不致命,返回 0 继续 */ }
|
||||
if(rbyte) *rbyte=rbuf[32]; /* PATCH_SEM/FINISH: sizeof(rxd)-4 = 32 */
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* FW_SCATTER:无头,走 FWDL 队列,分片 4096 */
|
||||
static int fw_scatter(const u8 *data,u32 len){
|
||||
u8 *scr=(u8*)g_tx_scratch.virt;
|
||||
while(len>0){
|
||||
u32 cur=len<FWDL_MAX_LEN?len:FWDL_MAX_LEN;
|
||||
memcpy_(scr,data,cur);
|
||||
__asm__ volatile("sfence":::"memory");
|
||||
if(tx_raw(&g_q_fwdl,g_tx_scratch.phys,cur)!=0) return -1;
|
||||
/* 等 fwdl dma_idx 追上(简化:轮询 dma_idx==head) */
|
||||
u32 r=g_q_fwdl.ring_base+g_q_fwdl.hw_idx*MT_RING_SIZE;
|
||||
u64 dl=dkm_rdtsc()+dkm_tsc_per_ms*200;
|
||||
while(bar_rr(r+0x0c)!=g_q_fwdl.head && dkm_rdtsc()<dl) __asm__ volatile("pause");
|
||||
data+=cur; len-=cur;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int mcu_init_download(u32 addr,u32 len,u32 mode){
|
||||
struct { u32 addr,len,mode; } req={addr,len,mode};
|
||||
int cmd = (addr==0x900000)?MCU_CMD_PATCH_START_REQ:MCU_CMD_TARGET_ADDRESS_LEN_REQ;
|
||||
return mcu_send(cmd,0,&req,sizeof(req),1,0);
|
||||
}
|
||||
|
||||
/* ===== driver own / wfsys reset / dma ===== */
|
||||
static int drv_own(void){
|
||||
for(int i=0;i<10;i++){
|
||||
reg_wr(MT_CONN_ON_LPCTL,PCIE_LPCR_HOST_CLR_OWN);
|
||||
if(poll_reg(MT_CONN_ON_LPCTL,PCIE_LPCR_HOST_OWN_SYNC,0,50)==0) return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static int fw_own(void){
|
||||
for(int i=0;i<10;i++){
|
||||
reg_wr(MT_CONN_ON_LPCTL,PCIE_LPCR_HOST_SET_OWN);
|
||||
if(poll_reg(MT_CONN_ON_LPCTL,PCIE_LPCR_HOST_OWN_SYNC,PCIE_LPCR_HOST_OWN_SYNC,50)==0) return 0;
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
static int top_drv_own(void){
|
||||
reg_wr(MT_TOP_LPCR_HOST_BAND0,MT_TOP_LPCR_HOST_DRV_OWN);
|
||||
return poll_reg(MT_TOP_LPCR_HOST_BAND0,MT_TOP_LPCR_HOST_FW_OWN,0,500);
|
||||
}
|
||||
static int wfsys_reset(void){
|
||||
reg_clr(MT_WFSYS_RST,WFSYS_SW_RST_B);
|
||||
dkm_delay_ms(50);
|
||||
reg_set(MT_WFSYS_RST,WFSYS_SW_RST_B);
|
||||
return poll_reg(MT_WFSYS_RST,WFSYS_SW_INIT_DONE,WFSYS_SW_INIT_DONE,500);
|
||||
}
|
||||
|
||||
static int dma_disable(int force){
|
||||
bar_clr(MT_WFDMA0_GLO_CFG,
|
||||
MT_WFDMA0_GLO_CFG_TX_DMA_EN|MT_WFDMA0_GLO_CFG_RX_DMA_EN|
|
||||
MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN|
|
||||
MT_WFDMA0_GLO_CFG_OMIT_TX_INFO|MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
|
||||
if(poll_bar(MT_WFDMA0_GLO_CFG,MT_WFDMA0_GLO_CFG_TX_DMA_BUSY|MT_WFDMA0_GLO_CFG_RX_DMA_BUSY,0,100)!=0)
|
||||
return -1;
|
||||
bar_clr(MT_WFDMA0_GLO_CFG_EXT0,MT_WFDMA0_GLO_CFG_EXT0_CSR_TX_DMASHDL_EN);
|
||||
reg_set(MT_DMASHDL_SW_CONTROL,MT_DMASHDL_DMASHDL_BYPASS);
|
||||
if(force){
|
||||
bar_clr(MT_WFDMA0_RST,MT_WFDMA0_RST_DMASHDL_ALL_RST|MT_WFDMA0_RST_LOGIC_RST);
|
||||
bar_set(MT_WFDMA0_RST,MT_WFDMA0_RST_DMASHDL_ALL_RST|MT_WFDMA0_RST_LOGIC_RST);
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static int dma_enable(void){
|
||||
bar_wr(MT_WFDMA0_RST_DTX_PTR,~0u);
|
||||
bar_wr(MT_WFDMA0_PRI_DLY_INT_CFG0,0);
|
||||
bar_set(MT_WFDMA0_GLO_CFG,
|
||||
MT_WFDMA0_GLO_CFG_TX_WB_DDONE|MT_WFDMA0_GLO_CFG_FIFO_LITTLE_ENDIAN|
|
||||
MT_WFDMA0_GLO_CFG_CLK_GAT_DIS|MT_WFDMA0_GLO_CFG_OMIT_TX_INFO|
|
||||
(3u<<MT_WFDMA0_GLO_CFG_DMA_SIZE_SHIFT)|MT_WFDMA0_GLO_CFG_RX_WB_DDONE|
|
||||
MT_WFDMA0_GLO_CFG_CSR_DISP_BASE_PTR_CHAIN_EN|MT_WFDMA0_GLO_CFG_OMIT_RX_INFO_PFET2);
|
||||
bar_set(MT_WFDMA0_GLO_CFG,MT_WFDMA0_GLO_CFG_TX_DMA_EN|MT_WFDMA0_GLO_CFG_RX_DMA_EN);
|
||||
bar_set(MT_WFDMA_DUMMY_CR,MT_WFDMA_NEED_REINIT);
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* RX MCU ring 填充 buffer */
|
||||
static int rx_fill(void){
|
||||
u64 pages=(RX_NDESC*2048+4095)/4096;
|
||||
if(g_api->dma->alloc_pages(pages,4096,0xFFFFFFFFull,&g_rx_bufs)!=0) return -1;
|
||||
memset_(g_rx_bufs.virt,0,pages*4096);
|
||||
for(u32 i=0;i<RX_NDESC;i++){
|
||||
struct mt_desc *d=&g_q_rxmcu.desc[i];
|
||||
u64 bp=g_rx_bufs.phys+(u64)i*2048;
|
||||
d->buf0=(u32)bp;
|
||||
d->buf1=0;
|
||||
d->info=0;
|
||||
d->ctrl=((2048u&0x3fff)<<MT_DMA_CTL_SD_LEN0_SHIFT);
|
||||
}
|
||||
__asm__ volatile("sfence":::"memory");
|
||||
/* cpu_idx 指到最后,表示全部 buffer 可用 */
|
||||
u32 r=g_q_rxmcu.ring_base+g_q_rxmcu.hw_idx*MT_RING_SIZE;
|
||||
bar_wr(r+0x08,RX_NDESC-1);
|
||||
g_q_rxmcu.head=0;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int dma_init(void){
|
||||
if(dma_disable(1)!=0){ rlog("[mt7920] dma_disable timeout\n"); }
|
||||
if(q_alloc(&g_q_wm,256,MT_TX_RING_BASE,TXQ_MCU_WM)!=0) return -1;
|
||||
if(q_alloc(&g_q_fwdl,128,MT_TX_RING_BASE,TXQ_FWDL)!=0) return -1;
|
||||
if(q_alloc(&g_q_rxmcu,RX_NDESC,MT_RX_EVENT_RING_BASE,RXQ_MCU_WM)!=0) return -1;
|
||||
q_sync(&g_q_wm);
|
||||
q_sync(&g_q_fwdl);
|
||||
q_sync(&g_q_rxmcu);
|
||||
if(rx_fill()!=0) return -1;
|
||||
dma_enable();
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ===== 固件下载 ===== */
|
||||
static int load_patch(const u8 *fw,u64 fwsz){
|
||||
u8 sem=0;
|
||||
struct { u32 op; } semreq;
|
||||
semreq.op=PATCH_SEM_GET;
|
||||
mcu_send(MCU_CMD_PATCH_SEM_CONTROL,0,&semreq,sizeof(semreq),1,&sem);
|
||||
rhex("[mt7920] patch sem=",sem);
|
||||
if(sem==PATCH_IS_DL) return 0;
|
||||
if(sem!=PATCH_NOT_DL_SEM_SUCCESS){ rlog("[mt7920] patch sem fail\n"); }
|
||||
|
||||
if(fwsz<sizeof(struct patch_hdr)){ mt_panic("MT7920-E20 PATCH FW TOO SMALL"); return -1; }
|
||||
const struct patch_hdr *h=(const struct patch_hdr*)fw;
|
||||
u32 nreg=be32((const u8*)&h->desc.n_region);
|
||||
rhex("[mt7920] patch regions=",nreg);
|
||||
|
||||
int ret=0;
|
||||
for(u32 i=0;i<nreg;i++){
|
||||
const struct patch_sec *s=(const struct patch_sec*)(fw+sizeof(struct patch_hdr)+i*sizeof(struct patch_sec));
|
||||
if((be32((const u8*)&s->type)&PATCH_SEC_TYPE_MASK)!=PATCH_SEC_TYPE_INFO){ mt_panic("MT7920-E21 PATCH SEC TYPE"); ret=-1; break; }
|
||||
u32 addr=be32((const u8*)&s->addr);
|
||||
u32 len=be32((const u8*)&s->len);
|
||||
u32 offs=be32((const u8*)&s->offs);
|
||||
u32 mode=DL_MODE_NEED_RSP; /* plain,MT7920 patch 非加密段 */
|
||||
rhex("[mt7920] patch addr=",addr);
|
||||
rhex("[mt7920] patch len=",len);
|
||||
if(mcu_init_download(addr,len,mode)!=0){ rlog("[mt7920] init_download fail\n"); ret=-1; break; }
|
||||
if(fw_scatter(fw+offs,len)!=0){ rlog("[mt7920] scatter fail\n"); ret=-1; break; }
|
||||
}
|
||||
/* PATCH_FINISH */
|
||||
struct { u8 check_crc; u8 rsv[3]; } fin; memset_(&fin,0,sizeof(fin));
|
||||
mcu_send(MCU_CMD_PATCH_FINISH_REQ,0,&fin,sizeof(fin),1,0);
|
||||
|
||||
/* release sem */
|
||||
semreq.op=PATCH_SEM_RELEASE;
|
||||
mcu_send(MCU_CMD_PATCH_SEM_CONTROL,0,&semreq,sizeof(semreq),1,&sem);
|
||||
return ret;
|
||||
}
|
||||
|
||||
static int load_ram(const u8 *fw,u64 fwsz){
|
||||
if(fwsz<sizeof(struct fw_trailer)){ mt_panic("MT7920-E22 RAM FW TOO SMALL"); return -1; }
|
||||
const struct fw_trailer *tr=(const struct fw_trailer*)(fw+fwsz-sizeof(struct fw_trailer));
|
||||
u8 nreg=tr->n_region;
|
||||
rhex("[mt7920] ram regions=",nreg);
|
||||
u32 offset=0, override=0, option=0;
|
||||
for(u8 i=0;i<nreg;i++){
|
||||
const struct fw_region *rg=(const struct fw_region*)((const u8*)tr-((u32)(nreg-i))*sizeof(struct fw_region));
|
||||
u32 len=le32((const u8*)&rg->len);
|
||||
u32 addr=le32((const u8*)&rg->addr);
|
||||
u32 mode=DL_MODE_NEED_RSP;
|
||||
if(rg->feature_set&FW_FEATURE_NON_DL){ offset+=len; continue; }
|
||||
if(rg->feature_set&FW_FEATURE_OVERRIDE_ADDR) override=addr;
|
||||
rhex("[mt7920] ram addr=",addr);
|
||||
rhex("[mt7920] ram len=",len);
|
||||
if(mcu_init_download(addr,len,mode)!=0){ rlog("[mt7920] ram init_download fail\n"); return -1; }
|
||||
if(fw_scatter(fw+offset,len)!=0){ rlog("[mt7920] ram scatter fail\n"); return -1; }
|
||||
offset+=len;
|
||||
}
|
||||
if(override) option|=FW_START_OVERRIDE;
|
||||
struct { u32 option,addr; } sreq={option,override};
|
||||
mcu_send(MCU_CMD_FW_START_REQ,0,&sreq,sizeof(sreq),1,0);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int load_firmware(void){
|
||||
const u8 *patch,*ram; u64 psz,rsz;
|
||||
if(fw_find("fw:mt7920_patch",&patch,&psz)!=0){ mt_panic("MT7920-E23 PATCH FW MODULE MISSING"); return -1; }
|
||||
if(fw_find("fw:mt7920_ram",&ram,&rsz)!=0){ mt_panic("MT7920-E24 RAM FW MODULE MISSING"); return -1; }
|
||||
rhex("[mt7920] patch fw size=",psz);
|
||||
rhex("[mt7920] ram fw size=",rsz);
|
||||
|
||||
/* NIC_POWER_CTRL restart + 等 FW_PWR_ON */
|
||||
struct { u8 pm; u8 rsv[3]; } pr; memset_(&pr,0,sizeof(pr)); pr.pm=1;
|
||||
mcu_send(MCU_CMD_NIC_POWER_CTRL,0,&pr,sizeof(pr),0,0);
|
||||
if(poll_reg(MT_CONN_ON_MISC,MT_TOP_MISC_FW_STATE,MT_TOP_MISC2_FW_PWR_ON,1000)!=0)
|
||||
rlog("[mt7920] WARN MCU not ready for fw dl\n");
|
||||
|
||||
if(load_patch(patch,psz)!=0){ mt_panic("MT7920-E25 PATCH DOWNLOAD FAILED"); return -1; }
|
||||
rlog("[mt7920] patch downloaded\n");
|
||||
if(load_ram(ram,rsz)!=0){ mt_panic("MT7920-E26 RAM DOWNLOAD FAILED"); return -1; }
|
||||
rlog("[mt7920] ram downloaded\n");
|
||||
|
||||
if(poll_reg(MT_CONN_ON_MISC,MT_TOP_MISC2_FW_N9_RDY,MT_TOP_MISC2_FW_N9_RDY,1500)!=0){
|
||||
mt_panic("MT7920-E27 FIRMWARE N9 NOT READY");
|
||||
return -1;
|
||||
}
|
||||
rlog("[mt7920] N9 firmware ready\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* ===== netdev 回调(扫描/关联未实现,显式 panic) ===== */
|
||||
static int mt_scan_start(void *c){(void)c;mt_panic("MT7920-E10 WIFI SCAN NOT IMPLEMENTED");return -1;}
|
||||
static int mt_scan_count(void *c){(void)c;mt_panic("MT7920-E10 WIFI SCAN NOT IMPLEMENTED");return 0;}
|
||||
static int mt_scan_result(void *c,u32 n,struct dkm_net_scan_result *o){(void)c;(void)n;(void)o;mt_panic("MT7920-E10 WIFI SCAN NOT IMPLEMENTED");return -1;}
|
||||
static int mt_connect(void *c,const char *s,const char *p){(void)c;(void)s;(void)p;mt_panic("MT7920-E11 WLAN CONNECT NOT IMPLEMENTED");return -1;}
|
||||
static int mt_disconnect(void *c){(void)c;mt_panic("MT7920-E12 WLAN DISCONNECT NOT IMPLEMENTED");return -1;}
|
||||
static int mt_is_wireless(void *c){(void)c;return 1;}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
int driver_init(const struct dkm_kernel_api *api,struct dkm_driver_handle *handle){
|
||||
(void)handle;
|
||||
if(!api||!api->log) return -1;
|
||||
dkm_tsc_calibrate();
|
||||
g_api=api; g_log=(struct dkm_log_api*)api->log;
|
||||
dkm_instr_init(api);
|
||||
rlog("[mt7920] driver_init entered\n");
|
||||
|
||||
if(mt_find()!=0){ rlog("[mt7920] 14c3:7920 not found\n"); return 0; }
|
||||
rhex("[mt7920] b:d:f=",((u64)g_bus<<16)|((u64)g_dev<<8)|g_func);
|
||||
|
||||
u32 cmd=pci_rd(g_bus,g_dev,g_func,0x04);
|
||||
cmd|=(1u<<1)|(1u<<2);
|
||||
pci_wr(g_bus,g_dev,g_func,0x04,cmd);
|
||||
|
||||
u32 bar0=pci_rd(g_bus,g_dev,g_func,0x10);
|
||||
if(bar0&1u){ mt_panic("MT7920-E02 BAR0 IS IO"); return -1; }
|
||||
u64 phys=(u64)(bar0&0xFFFFFFF0u);
|
||||
if((bar0&0x6u)==0x4u) phys|=((u64)pci_rd(g_bus,g_dev,g_func,0x14)<<32);
|
||||
rhex("[mt7920] BAR0 phys=",phys);
|
||||
if(!phys){ mt_panic("MT7920-E02 BAR0 MISSING"); return -1; }
|
||||
if(!api->mm_map_mmio){ mt_panic("MT7920-E02 MMIO MAP API MISSING"); return -1; }
|
||||
void *va=api->mm_map_mmio(phys,0x200000); /* 2MB BAR0 窗口 */
|
||||
if(!va){ mt_panic("MT7920-E02 MMIO MAP FAILED"); return -1; }
|
||||
g_bar=(volatile u8*)va;
|
||||
|
||||
/* 先让固件 own,再取 driver own(对拍 probe 顺序) */
|
||||
fw_own();
|
||||
if(drv_own()!=0){ mt_panic("MT7920-E03 DRIVER OWN FAILED"); g_bar=0; return -1; }
|
||||
rlog("[mt7920] driver own ok\n");
|
||||
|
||||
u32 chip=reg_rr(MT_HW_CHIPID);
|
||||
u32 rev=reg_rr(MT_HW_REV);
|
||||
rhex("[mt7920] chipid=",chip);
|
||||
rhex("[mt7920] rev=",rev);
|
||||
|
||||
if(wfsys_reset()!=0){ rlog("[mt7920] WARN wfsys reset timeout\n"); }
|
||||
else rlog("[mt7920] wfsys reset done\n");
|
||||
|
||||
bar_wr(MT_WFDMA0_HOST_INT_ENA,0);
|
||||
bar_wr(MT_PCIE_MAC_INT_ENABLE,0xff);
|
||||
|
||||
if(dma_init()!=0){ mt_panic("MT7920-E04 DMA INIT FAILED"); g_bar=0; return -1; }
|
||||
rlog("[mt7920] dma init ok\n");
|
||||
|
||||
/* TX scratch */
|
||||
if(api->dma->alloc_pages((TX_SCRATCH_SZ+4095)/4096,4096,0xFFFFFFFFull,&g_tx_scratch)!=0){
|
||||
mt_panic("MT7920-E05 TX SCRATCH ALLOC FAILED");
|
||||
g_bar=0; return -1;
|
||||
}
|
||||
|
||||
/* MCU own via TOP LPCR,再下载固件 */
|
||||
if(top_drv_own()!=0){ rlog("[mt7920] WARN top drv own timeout\n"); }
|
||||
if(load_firmware()!=0){ mt_panic("MT7920-E06 FIRMWARE LOAD FAILED"); g_bar=0; return -1; }
|
||||
|
||||
/* 注册 netdev(link 需后续 phy/连接阶段才 up) */
|
||||
if(api->net&&api->net->register_device){
|
||||
struct dkm_net_device_desc nd; memset_(&nd,0,sizeof(nd));
|
||||
nd.name="wlan0";
|
||||
nd.flags=(1u<<3);
|
||||
nd.scan_start=mt_scan_start;
|
||||
nd.scan_count=mt_scan_count;
|
||||
nd.scan_result=mt_scan_result;
|
||||
nd.is_wireless=mt_is_wireless;
|
||||
nd.connect=mt_connect;
|
||||
nd.disconnect=mt_disconnect;
|
||||
int idx=api->net->register_device(&nd);
|
||||
rhex("[mt7920] netdev index=",(u64)(i32)idx);
|
||||
}
|
||||
rlog("[mt7920] init done (firmware running; scan/connect pending)\n");
|
||||
return 0;
|
||||
}
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
int driver_exit(struct dkm_driver_handle *handle){ (void)handle; g_bar=0; return 0; }
|
||||
@@ -784,7 +784,7 @@ static int virtio_net_tx_stub(void *ctx, const void *packet, u32 length) {
|
||||
(void)ctx; (void)packet;
|
||||
log_hex("[virtio_net] tx stub hit, len=", length);
|
||||
g_log->panic("VNET-E01 TX VIRTQUEUE NOT IMPLEMENTED (stub tx called)");
|
||||
return 0;
|
||||
return -1;
|
||||
}
|
||||
|
||||
static int virtio_net_rx_poll_stub(void *ctx, void *buffer, u32 capacity, u32 *out_length) {
|
||||
|
||||
@@ -64,6 +64,8 @@ static const struct wlan_device_id g_wlan_ids[] = {
|
||||
{0x168C, 0x0034, "AR9462", "ath9k"},
|
||||
{0x168C, 0x0036, "AR9565", "ath9k"},
|
||||
{0x168C, 0x003C, "AR9462-2", "ath9k"},
|
||||
/* MediaTek (14C3) — 由 mt7920.drv 独占,wlan 不注册 */
|
||||
{0x14C3, 0x7920, "MT7920", "mt7920"},
|
||||
/* Broadcom (14E4) — brcmfmac 家族 */
|
||||
{0x14E4, 0x43A0, "BCM4360", "brcmfmac"},
|
||||
{0x14E4, 0x4365, "BCM43142", "brcmfmac"},
|
||||
@@ -122,10 +124,10 @@ static void zero_bytes(void *p, u64 n) {
|
||||
/* ---- 严格错误策略骨架:原生/网守后端未落地,调用即 panic ---- */
|
||||
static struct dkm_log_api *g_log;
|
||||
|
||||
/* strict 模式 g_log->panic 不返回;fallback 模式返回,回调随后报错返回 */
|
||||
static void wlan_panic(const char *sym, const char *detail) {
|
||||
g_log->panic(sym);
|
||||
(void)detail;
|
||||
for (;;) __asm__ volatile("cli; hlt");
|
||||
}
|
||||
|
||||
static int wlan_scan_start(void *ctx) {
|
||||
@@ -192,6 +194,10 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
|
||||
u16 vendor = (u16)(vd & 0xffff);
|
||||
u16 did = (u16)(vd >> 16);
|
||||
if (vendor == 0x14C3 && did == 0x7920) {
|
||||
g_log->info("[wlan] MT7920 left to mt7920.drv");
|
||||
continue;
|
||||
}
|
||||
const struct wlan_device_id *hit = 0;
|
||||
for (u32 i = 0; i < sizeof(g_wlan_ids)/sizeof(g_wlan_ids[0]); i++) {
|
||||
if (g_wlan_ids[i].vendor == vendor && g_wlan_ids[i].did == did) {
|
||||
|
||||
+90
-56
@@ -562,7 +562,8 @@ static u32 xhci_pci_diag_code(void) {
|
||||
return 0x13;
|
||||
}
|
||||
|
||||
static int xhci_find(u8 *out_bus, u8 *out_dev, u8 *out_func) {
|
||||
static int xhci_find_nth(int nth, u8 *out_bus, u8 *out_dev, u8 *out_func) {
|
||||
int seen = 0;
|
||||
for (u16 bus = 0; bus < 256; bus++) {
|
||||
for (u8 dev = 0; dev < 32; dev++) {
|
||||
u32 vd = dkm_pci_read((u8)bus, dev, 0, PCI_VENDOR_ID);
|
||||
@@ -582,10 +583,13 @@ static int xhci_find(u8 *out_bus, u8 *out_dev, u8 *out_func) {
|
||||
if (class_code == XHCI_CLASS_SERIAL &&
|
||||
subclass == XHCI_SUBCLASS_USB &&
|
||||
prog_if == XHCI_PROGIF_XHCI) {
|
||||
*out_bus = (u8)bus;
|
||||
*out_dev = dev;
|
||||
*out_func = func;
|
||||
return 0;
|
||||
if (seen == nth) {
|
||||
*out_bus = (u8)bus;
|
||||
*out_dev = dev;
|
||||
*out_func = func;
|
||||
return 0;
|
||||
}
|
||||
seen++;
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -1104,8 +1108,12 @@ static int xhci_reset_port(u32 port_idx) {
|
||||
/* Already enabled? */
|
||||
if (portsc & PORTSC_PED) return 0;
|
||||
|
||||
/* Clear any change bits (W1C), then assert port reset */
|
||||
mmio_write32(port_off, portsc | PORTSC_PR);
|
||||
/* 只置 PR,并清掉 RW1C 位。把读到的 PORTSC 原样或上 PR 会把
|
||||
* PED=0 和已经为 1 的变化位写回去,实机上复位经常起不来。 */
|
||||
u32 cmd = portsc & ~((1u << 1) | PORTSC_PR | 0x00FE0000u);
|
||||
cmd |= PORTSC_PR;
|
||||
if (portsc & (1u << 9)) cmd |= (1u << 9);
|
||||
mmio_write32(port_off, cmd);
|
||||
|
||||
/* Wait for PED (Port Enabled) with 500ms timeout */
|
||||
u64 deadline = dkm_rdtsc() + dkm_tsc_per_ms * 500;
|
||||
@@ -1920,6 +1928,8 @@ static int xhci_enum_msc_device(u32 port_idx) {
|
||||
* driver_init — main entry point
|
||||
* ================================================================ */
|
||||
|
||||
#define XHCI_TRY_NEXT do { xhci_nth++; if (xhci_nth < 4) goto again_ctrl; return 0; } while (0)
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
int driver_init(const struct dkm_kernel_api *api,
|
||||
struct dkm_driver_handle *handle) {
|
||||
@@ -1935,7 +1945,10 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
|
||||
/* ---- Phase 1: PCI discovery ---- */
|
||||
u8 bus = 0, dev = 0, func = 0;
|
||||
if (xhci_find(&bus, &dev, &func) != 0) {
|
||||
/* 实机常有不止一只 xHCI。U 盘可能不在第一只上,找不到 MSC 就试下一只。 */
|
||||
int xhci_nth = 0;
|
||||
again_ctrl:
|
||||
if (xhci_find_nth(xhci_nth, &bus, &dev, &func) != 0) {
|
||||
g_log->info("[xhci] xHCI controller not found");
|
||||
/* BUG-FIX: 不 halt。xhci 是可选驱动(manifest required=false),
|
||||
* 无 xHCI 的平台(Intel 6 系/纯 EHCI)必须继续引导到 EHCI/DSK,
|
||||
@@ -1955,6 +1968,18 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
log_hex("[xhci] vendor=", vd & 0xffff);
|
||||
log_hex("[xhci] device=", vd >> 16);
|
||||
|
||||
/* Intel PCH 默认把 USB2 口留在 EHCI。不把路由切到 xHCI,
|
||||
* U 盘在 xHCI 上永远没有 CCS,块设备就不会注册。 */
|
||||
if ((vd & 0xffff) == 0x8086) {
|
||||
u32 usb2_mask = dkm_pci_read(bus, dev, func, 0xD4);
|
||||
u32 usb3_mask = dkm_pci_read(bus, dev, func, 0xDC);
|
||||
if (usb2_mask) dkm_pci_write(bus, dev, func, 0xD0, usb2_mask);
|
||||
if (usb3_mask) dkm_pci_write(bus, dev, func, 0xD8, usb3_mask);
|
||||
log_hex("[xhci] intel usb2 route=", usb2_mask);
|
||||
log_hex("[xhci] intel usb3 route=", usb3_mask);
|
||||
dkm_delay_ms(200);
|
||||
}
|
||||
|
||||
/* Enable PCI MEM + BUSM, disable INTx (polling mode) */
|
||||
u32 command = dkm_pci_read(bus, dev, func, PCI_COMMAND) & 0xffff;
|
||||
command |= PCI_CMD_MEM | PCI_CMD_BUSM | (1u << 10);
|
||||
@@ -1968,7 +1993,7 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
if (bar0_lo & 1u) {
|
||||
g_log->warn("[xhci] BAR0 is IO space; unsupported");
|
||||
FB_FATAL(api, 0x02); /* 红: BAR0 是 IO 空间 */
|
||||
return 0;
|
||||
XHCI_TRY_NEXT;
|
||||
}
|
||||
if ((bar0_lo & 0x6u) == 0x4u) {
|
||||
bar_phys = ((u64)bar1_hi << 32) | (u64)(bar0_lo & 0xFFFFFFF0u);
|
||||
@@ -1984,7 +2009,7 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
if (!api->hhdm_offset || !bar_phys) {
|
||||
g_log->warn("[xhci] missing HHDM or BAR0; skip");
|
||||
FB_FATAL(api, 0x02); /* 红: 缺 HHDM/BAR */
|
||||
return 0;
|
||||
XHCI_TRY_NEXT;
|
||||
}
|
||||
|
||||
/* ---- Phase 1: MMIO mapping ---- */
|
||||
@@ -1992,14 +2017,14 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
if (!g_mmio) {
|
||||
g_log->error("[xhci] BAR MMIO unavailable; driver inactive");
|
||||
FB_FATAL(api, 0x03); /* 红: BAR MMIO 映射失败 */
|
||||
return 0;
|
||||
XHCI_TRY_NEXT;
|
||||
}
|
||||
|
||||
/* ---- Phase 1: Parse capabilities ---- */
|
||||
if (xhci_parse_caps() != 0) {
|
||||
g_log->error("[xhci] capability parse failed");
|
||||
FB_FATAL(api, 0x04); /* 红: capability 解析失败 */
|
||||
return 0;
|
||||
XHCI_TRY_NEXT;
|
||||
}
|
||||
|
||||
/* ---- Phase 1: BIOS Handoff ---- */
|
||||
@@ -2009,27 +2034,27 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
if (xhci_controller_reset() != 0) {
|
||||
g_log->error("[xhci] controller reset failed");
|
||||
FB_FATAL(api, 0x05); /* 红: 控制器 reset 失败 */
|
||||
return 0;
|
||||
XHCI_TRY_NEXT;
|
||||
}
|
||||
|
||||
/* ---- Phase 2: Setup Rings + DCBAA + Scratchpad ---- */
|
||||
if (!api->dma) {
|
||||
g_log->warn("[xhci] DMA API unavailable");
|
||||
FB_FATAL(api, 0x06); /* 红: DMA API 缺失 */
|
||||
return 0;
|
||||
XHCI_TRY_NEXT;
|
||||
}
|
||||
|
||||
if (xhci_setup_rings() != 0) {
|
||||
g_log->error("[xhci] ring setup failed");
|
||||
FB_FATAL(api, 0x06); /* 红: ring 初始化失败 */
|
||||
return 0;
|
||||
XHCI_TRY_NEXT;
|
||||
}
|
||||
|
||||
/* ---- Phase 2: Start Controller ---- */
|
||||
if (xhci_controller_start() != 0) {
|
||||
g_log->error("[xhci] controller start failed");
|
||||
FB_FATAL(api, 0x07); /* 红: 控制器启动失败 */
|
||||
return 0;
|
||||
XHCI_TRY_NEXT;
|
||||
}
|
||||
|
||||
/* ---- Phase 3: Port Scan + Device Enumeration ---- */
|
||||
@@ -2039,53 +2064,56 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
* attachment and update port status. Without this delay, PORTSC.CCS
|
||||
* may read 0 even though a device is physically connected.
|
||||
*/
|
||||
g_log->info("[xhci] waiting 100ms for port settle...");
|
||||
dkm_delay_ms(100);
|
||||
|
||||
g_msc.ready = 0;
|
||||
/* 控制器复位后端口掉电。先全部上电,再等 U 盘重新连接。
|
||||
* 20ms 就读 CCS 时,实机上的 U 盘还没出现,于是不会注册块设备。 */
|
||||
for (u32 port = 0; port < g_max_ports; port++) {
|
||||
u32 port_off = g_port_base + port * XHCI_PORT_STRIDE + XHCI_PORT_SC;
|
||||
u32 portsc = mmio_read32(port_off);
|
||||
if (g_ppc && !(portsc & (1u << 9))) {
|
||||
mmio_write32(port_off, portsc | (1u << 9));
|
||||
}
|
||||
}
|
||||
g_log->info("[xhci] waiting 1500ms for port settle...");
|
||||
dkm_delay_ms(1500);
|
||||
|
||||
/* Always log PORTSC for debugging, even if no device is connected */
|
||||
log_hex("[xhci] port=", port);
|
||||
log_hex("[xhci] PORTSC=", portsc);
|
||||
g_msc.ready = 0;
|
||||
int saw_ccs = 0;
|
||||
int saw_reset_fail = 0;
|
||||
for (int pass = 0; pass < 2 && !g_msc.ready; pass++) {
|
||||
if (pass == 1) {
|
||||
g_log->info("[xhci] second port scan");
|
||||
dkm_delay_ms(1500);
|
||||
}
|
||||
for (u32 port = 0; port < g_max_ports; port++) {
|
||||
u32 port_off = g_port_base + port * XHCI_PORT_STRIDE + XHCI_PORT_SC;
|
||||
u32 portsc = mmio_read32(port_off);
|
||||
|
||||
if (!(portsc & PORTSC_CCS)) {
|
||||
/*
|
||||
* If PPC (Per-Port Power Control) is supported, the port may
|
||||
* need to be powered on before CCS reflects device connection.
|
||||
* Set PP (Port Power) bit in PORTSC to enable port power.
|
||||
* If PPC=0, ports are always powered and this write is a no-op.
|
||||
*/
|
||||
if (g_ppc && !(portsc & (1u << 9))) {
|
||||
g_log->info("[xhci] enabling port power");
|
||||
mmio_write32(port_off, portsc | (1u << 9));
|
||||
/* Wait briefly for power to stabilize */
|
||||
dkm_delay_ms(20);
|
||||
portsc = mmio_read32(port_off);
|
||||
log_hex("[xhci] PORTSC after PP=", portsc);
|
||||
log_hex("[xhci] port=", port);
|
||||
log_hex("[xhci] PORTSC=", portsc);
|
||||
|
||||
if (!(portsc & PORTSC_CCS)) continue;
|
||||
|
||||
saw_ccs = 1;
|
||||
g_log->info("[xhci] device connected");
|
||||
|
||||
if (xhci_reset_port(port) != 0) {
|
||||
g_log->warn("[xhci] port reset failed");
|
||||
saw_reset_fail = 1;
|
||||
continue;
|
||||
}
|
||||
if (!(portsc & PORTSC_CCS)) continue; /* Still no device */
|
||||
g_log->info("[xhci] port reset OK");
|
||||
|
||||
if (xhci_enum_msc_device(port) == 0) {
|
||||
g_log->info("[xhci] MSC enumeration successful");
|
||||
break;
|
||||
}
|
||||
|
||||
g_log->warn("[xhci] MSC enumeration failed; trying next port");
|
||||
}
|
||||
|
||||
g_log->info("[xhci] device connected");
|
||||
|
||||
/* Port Reset */
|
||||
if (xhci_reset_port(port) != 0) {
|
||||
/* 严格错误策略插桩:端口复位失败 = 设备不可用,零降级 panic */
|
||||
g_log->panic("XHC-E01 PORT RESET FAILED");
|
||||
continue;
|
||||
}
|
||||
g_log->info("[xhci] port reset OK");
|
||||
|
||||
/* Try to enumerate as MSC device */
|
||||
if (xhci_enum_msc_device(port) == 0) {
|
||||
g_log->info("[xhci] MSC enumeration successful");
|
||||
break; /* First MSC device is enough for now */
|
||||
}
|
||||
|
||||
g_log->warn("[xhci] MSC enumeration failed; trying next port");
|
||||
}
|
||||
if (!g_msc.ready && saw_ccs && xhci_nth >= 3) {
|
||||
g_log->panic(saw_reset_fail ? "XHC-E01 PORT RESET FAILED"
|
||||
: "XHC-E02 MSC ENUM FAILED");
|
||||
}
|
||||
|
||||
/* ---- Phase 5: Register Block Device ---- */
|
||||
@@ -2105,12 +2133,18 @@ int driver_init(const struct dkm_kernel_api *api,
|
||||
}
|
||||
} else {
|
||||
g_log->info("[xhci] no MSC device found; block provider not registered");
|
||||
if (xhci_nth < 3) {
|
||||
xhci_nth++;
|
||||
g_log->info("[xhci] trying next controller");
|
||||
goto again_ctrl;
|
||||
}
|
||||
FB_FATAL(api, 0x08); /* 黄: 所有端口无设备/枚举全部失败 */
|
||||
}
|
||||
|
||||
g_log->info("[xhci] driver ready");
|
||||
return 0;
|
||||
}
|
||||
#undef XHCI_TRY_NEXT
|
||||
|
||||
__attribute__((visibility("default")))
|
||||
int driver_exit(struct dkm_driver_handle *handle) {
|
||||
|
||||
Reference in New Issue
Block a user