本文档是基于FPGA K7 SATA IP控制器的SATA接口调试记录,接口遵循标准的ACHI协议。
操作系统内核版本:5.4.18
由于K7PCIE只有3个bar,AHCI协议规定SATA控制器是在第四个BAR上,另外由于PCIE配置空间设备类寄存器和能力寄存器未配置成sata设备,导致系统自带的驱动不能没生效。因此需要修改系统sata驱动并重新编译安装。
Sata驱动在内核目录/drivers/ata/下,对于ahci sata对于的驱动文件是ahci.c,单独编译ahci文件需要对该目录下的Makefile文件进行如下修改:
SPDX-License-Identifier: GPL-2.0
#将ahci.c文件编译成模块
CONFIG_SATA_AHCI := m
#CONFIG_PATA_PLATFORM := m
#CONFIG_PATA_OF_PLATFORM := m
#CONFIG_SATA_SIL24 := m
KERNEL_VERSION := $(shell uname -r)
KERNELDIR = /lib/modules/$(KERNEL_VERSION)/build
#INSTDIR = /lib/modules/$(KERNEL_VERSION)/kernel/drivers/ata
KERNEL := kernel-$(KERNEL_VERSION)
PWD := $(shell pwd)
EXTRA_CFLAGS += -DATA_DEBUG
#obj-$(CONFIG_ATA) += libata.o
# non-SFF interface
#obj-$(CONFIG_SATA_AHCI) += ahci.o libahci.o
#编译生成的模块名称为ahci_test.ko
obj-$(CONFIG_SATA_AHCI) := ahci_test.o
#模块有ahci.c文件编译生成
ahci_test-objs := ahci.o
#obj-$(CONFIG_SATA_ACARD_AHCI) += acard-ahci.o libahci.o
#obj-$(CONFIG_SATA_AHCI_SEATTLE) += ahci_seattle.o libahci.o libahci_platform.o
#obj-$(CONFIG_SATA_AHCI_PLATFORM) += ahci_platform.o libahci.o libahci_platform.o
#obj-$(CONFIG_SATA_FSL) += sata_fsl.o
#obj-$(CONFIG_SATA_GEMINI) += sata_gemini.o
#obj-$(CONFIG_SATA_INIC162X) += sata_inic162x.o
#obj-$(CONFIG_SATA_SIL24) += sata_sil24.o
#obj-$(CONFIG_SATA_SIL24) += sata_sil24_test.o
#sata_sil24_test-objs := sata_sil24.o
#obj-$(CONFIG_SATA_DWC) += sata_dwc_460ex.o
#obj-$(CONFIG_SATA_HIGHBANK) += sata_highbank.o libahci.o
#obj-$(CONFIG_AHCI_BRCM) += ahci_brcm.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_CEVA) += ahci_ceva.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_DA850) += ahci_da850.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_DM816) += ahci_dm816.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_IMX) += ahci_imx.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_MTK) += ahci_mtk.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_MVEBU) += ahci_mvebu.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_OCTEON) += ahci_octeon.o
#obj-$(CONFIG_AHCI_SUNXI) += ahci_sunxi.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_ST) += ahci_st.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_TEGRA) += ahci_tegra.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_XGENE) += ahci_xgene.o libahci.o libahci_platform.o
#obj-$(CONFIG_AHCI_QORIQ) += ahci_qoriq.o libahci.o libahci_platform.o
# SFF w/ custom DMA
#obj-$(CONFIG_PDC_ADMA) += pdc_adma.o
#obj-$(CONFIG_PATA_ARASAN_CF) += pata_arasan_cf.o
#obj-$(CONFIG_PATA_OCTEON_CF) += pata_octeon_cf.o
#obj-$(CONFIG_SATA_QSTOR) += sata_qstor.o
#obj-$(CONFIG_SATA_SX4) += sata_sx4.o
# SFF SATA w/ BMDMA
#obj-$(CONFIG_ATA_PIIX) += ata_piix.o
#obj-$(CONFIG_SATA_MV) += sata_mv.o
#obj-$(CONFIG_SATA_NV) += sata_nv.o
#obj-$(CONFIG_SATA_PROMISE) += sata_promise.o
#obj-$(CONFIG_SATA_RCAR) += sata_rcar.o
#obj-$(CONFIG_SATA_SIL) += sata_sil.o
#obj-$(CONFIG_SATA_SIS) += sata_sis.o
#obj-$(CONFIG_SATA_SVW) += sata_svw.o
#obj-$(CONFIG_SATA_ULI) += sata_uli.o
#obj-$(CONFIG_SATA_VIA) += sata_via.o
#obj-$(CONFIG_SATA_VITESSE) += sata_vsc.o
# SFF PATA w/ BMDMA
#obj-$(CONFIG_PATA_ALI) += pata_ali.o
#obj-$(CONFIG_PATA_AMD) += pata_amd.o
#obj-$(CONFIG_PATA_ARTOP) += pata_artop.o
#obj-$(CONFIG_PATA_ATIIXP) += pata_atiixp.o
#obj-$(CONFIG_PATA_ATP867X) += pata_atp867x.o
#obj-$(CONFIG_PATA_BK3710) += pata_bk3710.o
#obj-$(CONFIG_PATA_CMD64X) += pata_cmd64x.o
#obj-$(CONFIG_PATA_CS5520) += pata_cs5520.o
#obj-$(CONFIG_PATA_CS5530) += pata_cs5530.o
#obj-$(CONFIG_PATA_CS5535) += pata_cs5535.o
#obj-$(CONFIG_PATA_CS5536) += pata_cs5536.o
#obj-$(CONFIG_PATA_CYPRESS) += pata_cypress.o
#obj-$(CONFIG_PATA_EFAR) += pata_efar.o
#obj-$(CONFIG_PATA_EP93XX) += pata_ep93xx.o
#obj-$(CONFIG_PATA_FTIDE010) += pata_ftide010.o
#obj-$(CONFIG_PATA_HPT366) += pata_hpt366.o
#obj-$(CONFIG_PATA_HPT37X) += pata_hpt37x.o
#obj-$(CONFIG_PATA_HPT3X2N) += pata_hpt3x2n.o
#obj-$(CONFIG_PATA_HPT3X3) += pata_hpt3x3.o
#obj-$(CONFIG_PATA_ICSIDE) += pata_icside.o
#obj-$(CONFIG_PATA_IMX) += pata_imx.o
#obj-$(CONFIG_PATA_IT8213) += pata_it8213.o
#obj-$(CONFIG_PATA_IT821X) += pata_it821x.o
#obj-$(CONFIG_PATA_JMICRON) += pata_jmicron.o
#obj-$(CONFIG_PATA_MACIO) += pata_macio.o
#obj-$(CONFIG_PATA_MARVELL) += pata_marvell.o
#obj-$(CONFIG_PATA_MPC52xx) += pata_mpc52xx.o
#obj-$(CONFIG_PATA_NETCELL) += pata_netcell.o
#obj-$(CONFIG_PATA_NINJA32) += pata_ninja32.o
#obj-$(CONFIG_PATA_NS87415) += pata_ns87415.o
#obj-$(CONFIG_PATA_OLDPIIX) += pata_oldpiix.o
#obj-$(CONFIG_PATA_OPTIDMA) += pata_optidma.o
#obj-$(CONFIG_PATA_PDC2027X) += pata_pdc2027x.o
#obj-$(CONFIG_PATA_PDC_OLD) += pata_pdc202xx_old.o
#obj-$(CONFIG_PATA_RADISYS) += pata_radisys.o
#obj-$(CONFIG_PATA_RDC) += pata_rdc.o
#obj-$(CONFIG_PATA_SC1200) += pata_sc1200.o
#obj-$(CONFIG_PATA_SCH) += pata_sch.o
#obj-$(CONFIG_PATA_SERVERWORKS) += pata_serverworks.o
#obj-$(CONFIG_PATA_SIL680) += pata_sil680.o
#obj-$(CONFIG_PATA_SIS) += pata_sis.o
#obj-$(CONFIG_PATA_TOSHIBA) += pata_piccolo.o
#obj-$(CONFIG_PATA_TRIFLEX) += pata_triflex.o
#obj-$(CONFIG_PATA_VIA) += pata_via.o
#obj-$(CONFIG_PATA_WINBOND) += pata_sl82c105.o
# SFF PIO only
#obj-$(CONFIG_PATA_CMD640_PCI) += pata_cmd640.o
#obj-$(CONFIG_PATA_FALCON) += pata_falcon.o
#obj-$(CONFIG_PATA_GAYLE) += pata_gayle.o
#obj-$(CONFIG_PATA_BUDDHA) += pata_buddha.o
#obj-$(CONFIG_PATA_ISAPNP) += pata_isapnp.o
#obj-$(CONFIG_PATA_IXP4XX_CF) += pata_ixp4xx_cf.o
#obj-$(CONFIG_PATA_MPIIX) += pata_mpiix.o
#obj-$(CONFIG_PATA_NS87410) += pata_ns87410.o
#obj-$(CONFIG_PATA_OPTI) += pata_opti.o
#obj-$(CONFIG_PATA_PCMCIA) += pata_pcmcia.o
#obj-$(CONFIG_PATA_PALMLD) += pata_palmld.o
#obj-$(CONFIG_PATA_PLATFORM) += pata_platform.o
#obj-$(CONFIG_PATA_PLATFORM) += pata_platform_test.o
#pata_platform_test-objs := pata_platform.o
#obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform.o
#obj-$(CONFIG_PATA_OF_PLATFORM) += pata_of_platform_test.o
#pata_of_platform_test-objs := pata_of_platform.o
#obj-$(CONFIG_PATA_RB532) += pata_rb532_cf.o
#obj-$(CONFIG_PATA_RZ1000) += pata_rz1000.o
#obj-$(CONFIG_PATA_SAMSUNG_CF) += pata_samsung_cf.o
#obj-$(CONFIG_PATA_PXA) += pata_pxa.o
# Should be last but two libata driver
#obj-$(CONFIG_PATA_ACPI) += pata_acpi.o
# Should be last but one libata driver
#obj-$(CONFIG_ATA_GENERIC) += ata_generic.o
# Should be last libata driver
#obj-$(CONFIG_PATA_LEGACY) += pata_legacy.o
#libata-y := libata-core.o libata-scsi.o libata-eh.o \
# libata-transport.o libata-trace.o
#libata-$(CONFIG_ATA_SFF) += libata-sff.o
#libata-$(CONFIG_SATA_PMP) += libata-pmp.o
#libata-$(CONFIG_ATA_ACPI) += libata-acpi.o
#libata-$(CONFIG_SATA_ZPODD) += libata-zpodd.o
all: prepare
$(MAKE) -C $(KERNELDIR) M=$(PWD) modules
cp *.ko $(KERNEL)/
prepare:
rm -rf $(KERNEL)
mkdir $(KERNEL)
clean:
rm -f *.o *.ko .*.cmd *.mod.* *.unsigned *.order *.symvers .*.cmd.* .*.ko.* .*.mod.o.* .*.o.* *.mod
rm -f -r .tmp_versions
rm -rf $(KERNEL)
ahci驱动是一个pcie驱动,要使该驱动和我们的pcie设备匹配,需要在设备信息表ahci_pci_tbl[]中增加对应的FPGA pcie设备信息,我这里PCIE厂家id是0x7018,设备id是0x8080,修改如下所示:
{ PCI_DEVICE(0x7018, 0x8080), board_ahci},
由于系统本身已经安装了ahci.ko驱动因此还需要修改驱动名称,否则安装相同的驱动会报驱动已安装错误。如驱动名称为“ahci_test”修改ahci.c文件中宏定义如下:
#define DRV_NAME "ahci_test"
完成以上修改后编译、安装驱动后/dev目录下依然未生成sata盘对应的设备节点文件。
dmesg命令查看内核打印信息发现未打印端口相关信息。通过查看驱动代码发现读取端口映射寄存器为0。读取端口映射寄存器代码如下:
手动将该寄存器0x7100000c(0x71000000为sata控制器bar基地址)置1后重新安装驱动,/dev/目录下依然未生成sata设备文件。dmesg查看内核驱动打印信息显示端口状态为link down。
查看端口状态寄存器0x71000128(0x71000100为端口0寄存器基地址)的值为0x30,说明端口sata设备确实没有link up。 将端口速率设置寄存器0x71080020设置成1,将sata3.0 改成sata2.0(该寄存器的值和端口速率对应关系为:0:sata1.0 ,1:sata2.0,2:sata3.0)。
重新安装驱动在/dev/目录下成功生成了sda设备文件。此时再次读取端口状态寄存器0x71000128值为0x123。
为了使驱动安装后自动配置以上两个寄存器,将以上两个寄存器配置在驱动中通过代码实现如下:
为了后续调试时能够隔离软件问题,梳理出以下初始化sata控制器步骤(memtool是内存读写工具):
1、进根权限
sudo su 输入密码
2、使能pcie设备
setpci -d 0731:8000 4.B=6
3、复位sata控制器HBA_HOST_GHC
memtool mw 0x71000004 0x01
4、设置HBA_HOST_CAP寄存器
memtool mw 0x71000000 0x6F36FF05
5、读取HBA_HOST_CAP寄存器
memtool md 0x71000000
6、设置端口映射寄存器HBA_HOST_PI
memtool mw 0x7100000c 0x1
7、HBA_PORT_CMD寄存器写0
memtool mw 0x71000118 0x0
8、HBA_HOST_BISTCR寄存器写0x5700
memtool mw 0x710000a4 0x5700
9、读取HBA_HOST_BISTCR寄存器写
memtool md 0x710000a4
10、读取HBA_PORT_CMD寄存器,读取的值为0x4
memtool md 0x71000118
11、HBA_PORT_CMD第4位置1
memtool mw 0x71000118 0x14
12、HBA_PORT_CMD第1位置1
memtool mw 0x71000118 0x16
13、读HBA_PORT_SSTS寄存器,寄存器第0位或者第1位需要置1才link up
memtool md 0x71000128
如果无法link up 需要执行完步骤1-6后设置0x71080020寄存器,将sata3.0 改成sata1.0
memtool mw 0x71080020 0x1
然后执行步骤7-13
参考手册《DWC_ahsata_databook.pdf》
简单梳理了几个关键的数据读写盘相关接口,后续有时间再深入研究。
struct ata_port_operations ahci_ops = {
.inherits = &sata_pmp_port_ops,
.qc_defer = ahci_pmp_qc_defer,
.qc_prep = ahci_qc_prep,
.qc_issue = ahci_qc_issue,
.qc_fill_rtf = ahci_qc_fill_rtf,
.freeze = ahci_freeze,
.thaw = ahci_thaw,
.softreset = ahci_softreset,
.hardreset = ahci_hardreset,
.postreset = ahci_postreset,
.pmp_softreset = ahci_softreset,
.error_handler = ahci_error_handler,
.post_internal_cmd = ahci_post_internal_cmd,
.dev_config = ahci_dev_config,
.scr_read = ahci_scr_read,
.scr_write = ahci_scr_write,
.pmp_attach = ahci_pmp_attach,
.pmp_detach = ahci_pmp_detach,
.set_lpm = ahci_set_lpm,
.em_show = ahci_led_show,
.em_store = ahci_led_store,
.sw_activity_show = ahci_activity_show,
.sw_activity_store = ahci_activity_store,
.transmit_led_message = ahci_transmit_led_message,
#ifdef CONFIG_PM
.port_suspend = ahci_port_suspend,
.port_resume = ahci_port_resume,
#endif
.port_start = ahci_port_start,
.port_stop = ahci_port_stop,
};
EXPORT_SYMBOL_GPL(ahci_ops);
#命令填充
.qc_prep = ahci_qc_prep,
#命令提交
.qc_issue = ahci_qc_issue,
#初始化sata控制器
ahci_pci_init_controller
#注册相关设备文件,生成/dev/sda设备
int ahci_host_activate(struct ata_host *host, struct scsi_host_template *sht)