该验证使用eth1网口作为验证对象,验证过程中会修改PHY的寄存器,不要使用此网口通信。
以下以GE类型的PHY读写为例。
cd /opt
tar -xzvf Ascend310B-source.tar.gz
cd Ascend310B-source/dtb/dts/hi1910b/hi1910BL/product
vim hi1910B-pinctrl-M100-B51.dtsi
pmx_io: pinmux@a0140000 {
compatible = "pinctrl-single", "pinctrl-single1";
reg = <0x0 0xa0140000 0x0 0x9c>;
#gpio-range-cells = <3>;
pinctrl-single,register-width = <32>;
pinctrl-single,function-mask = <7>;
pinctrl-names = "default", "idle";
pinctrl-0 = <&mdc1_pmx_func &mdio1_pmx_func>;
pinctrl-1 = <&mdc1_pmx_idle &mdc1_pmx_idle>;
mdc1_pmx_func: mdc1_pmx_func {
pinctrl-single,pins = <0x70 0x0>;
};
mdc1_pmx_idle: mdc1_pmx_idle {
pinctrl-single,pins = <0x70 0x0>;
};
mdio1_pmx_func: mdio1_pmx_func {
pinctrl-single,pins = <0x74 0x0>;
};
mdio1_pmx_idle: mdio1_pmx_idle {
pinctrl-single,pins = <0x74 0x0>;
};
};
以Atlas 200I DK A2 开发者套件的配置为例。
cd /opt/Ascend310B-source
bash build.sh dtb
出现如下回显,且生成“dt.img”文件表示编译内核DTB文件成功。
generate /opt/Ascend310B-source/output/dt.img success! sign /opt/Ascend310B-source/output/dt.img success!
编译后的dt.img文件会自动存放于“Ascend310B-source/output”目录下。
cd /opt/Ascend310B-source
bash build.sh kernelSource
出现如下类似回显表示编译成功,“/linux-4.19”为生成内核源码路径。
/opt/Ascend310B-source/driver kernel_directory is [/opt/Ascend310B-source/driver/kernel/linux-4.19] generate kernel source success!
cd /opt/Ascend310B-source/driver/drivers
mkdir usr
cd usr
vim hns_mdio.c
添加如下代码,配置完成后,按“Esc”键,再执行:wq!保存修改,并按“Enter”键退出。
直接拷贝文档中代码到Linux系统中使用可能有格式不兼容问题,例如空格与Tab键使用错误,若出现类似报错,请先在Linux系统中调整代码格式正确。
#include <linux/errno.h>
#include <linux/etherdevice.h>
#include <linux/init.h>
#include <linux/of.h>
#include <linux/platform_device.h>
#include <linux/kernel.h>
#include <linux/cdev.h>
#include <linux/module.h>
#include <linux/netdevice.h>
#include <linux/of_platform.h>
#include <linux/phy.h>
#include <linux/regmap.h>
#include <linux/version.h>
#include <linux/of_address.h>
#include <linux/of_mdio.h>
#include <linux/securec.h>
#define MDIO_CDEV_MINORS 2
#define PHY_ADDR_FIXED 0
#define MDIO_CDEV_NAME "davinci_mdio_daemo"
#define MDIO_DRV_NAME "HiAscend_MDIO_Daemo"
#define MDIO_BUS_NAME "Hisilicon Ascend MII Bus Daemo"
#define MDIO_TIMEOUT 1000000
/* cfg phy bit map */
#define MDIO_CMD_ST_S 12
#define MDIO_CMD_START_B 14
#define MDIO_CMD_PRTAD_S 5
#define MDIO_CMD_OP_S 10
#define MDIO_CMD_DEVAD_M 0x1f
#define MDIO_CMD_DEVAD_S 0
#define MDIO_CMD_PRTAD_M 0x1f
/* mdio reg */
#define MDIO_RDATA_REG 0xc
#define MDIO_STA_REG 0x10
#define MDIO_COMMAND_REG 0x0
#define MDIO_ADDR_REG 0x4
#define MDIO_WDATA_REG 0x8
#define MDIO_WDATA_DATA_M 0xffff
#define MDIO_WDATA_DATA_S 0
#define MDIO_RDATA_DATA_M 0xffff
#define MDIO_RDATA_DATA_S 0
#define MDIO_ADDR_DATA_M 0xffff
#define MDIO_ADDR_DATA_S 0
#define MDIO_STATE_STA_B 0
enum mdio_st_clause {
MDIO_ST_CLAUSE_45 = 0,
MDIO_ST_CLAUSE_22
};
enum {
MEM_MDIO_IOBASE,
MEM_SYSCTRL_IOBASE,
MEM_IOBASE_MAX,
};
enum mdio_c22_op_seq {
MDIO_C22_WRITE = 1,
MDIO_C22_READ = 2
};
struct peri_sc_mdio_reg {
u16 mdio_clk_en;
u16 mdio_clk_dis;
u16 mdio_reset_req;
u16 mdio_reset_dreq;
u16 mdio_ctrl;
u16 mdio_clk_st;
u16 mdio_reset_st;
};
enum mdio_c45_op_seq {
MDIO_C45_WRITE_ADDR = 0,
MDIO_C45_WRITE_DATA,
MDIO_C45_READ_INCREMENT,
MDIO_C45_READ
};
struct hns_mdio_device {
void *vbase; /* mdio reg base address */
struct regmap *subctrl_vbase;
const struct peri_sc_mdio_reg *sc_reg;
struct platform_device *pdev;
struct mii_bus *bus;
struct cdev mdio_cdev;
struct class *mdio_cdev_cls;
dev_t mdio_devno;
};
static struct mii_bus *hns_mdiobus = NULL;
static void mdio_write_reg(void *base, u32 reg, u32 value)
{
u8 __iomem *reg_addr = (u8 __iomem *)base;
writel_relaxed(value, reg_addr + reg);
}
#define MDIO_WRITE_REG(a, reg, value) mdio_write_reg((a)->vbase, (reg), (value))
static u32 mdio_read_reg(void *base, u32 reg)
{
u8 __iomem *reg_addr = (u8 __iomem *)base;
return readl_relaxed(reg_addr + reg);
}
#define mdio_set_field(origin, mask, shift, val) do { \
(origin) &= (~((mask) << (shift))); \
(origin) |= (((val) & (mask)) << (shift)); \
} while (0)
#define mdio_get_field(origin, mask, shift) (((origin) >> (shift)) & (mask))
static void mdio_set_reg_field(void *base, u32 reg, u32 mask, u32 shift, u32 val)
{
u32 origin = mdio_read_reg(base, reg);
mdio_set_field(origin, mask, shift, val);
mdio_write_reg(base, reg, origin);
}
#define MDIO_SET_REG_FIELD(dev, reg, mask, shift, val) mdio_set_reg_field((dev)->vbase, (reg), (mask), (shift), (val))
static u32 mdio_get_reg_field(void *base, u32 reg, u32 mask, u32 shift)
{
u32 origin;
origin = mdio_read_reg(base, reg);
return mdio_get_field(origin, mask, shift);
}
#define MDIO_GET_REG_FIELD(dev, reg, mask, shift) mdio_get_reg_field((dev)->vbase, (reg), (mask), (shift))
#define MDIO_GET_REG_BIT(dev, reg, bit) mdio_get_reg_field((dev)->vbase, (reg), 0x1ull, (bit))
static int hns_mdio_wait_ready(struct mii_bus *bus)
{
struct hns_mdio_device *mdio_dev = bus->priv;
u32 cmd_reg_value = 0;
int i;
/* waitting for MDIO_COMMAND_REG 's mdio_start==0 */
/* after that can do read or write */
for (i = 0; i < MDIO_TIMEOUT; i++) {
cmd_reg_value = MDIO_GET_REG_BIT(mdio_dev, MDIO_COMMAND_REG, MDIO_CMD_START_B);
if (!cmd_reg_value) {
break;
}
}
if ((i == MDIO_TIMEOUT) && cmd_reg_value) {
printk(KERN_ERR "hns mdio wait timeout.\n");
return -ETIMEDOUT;
}
return 0;
}
static void hns_mdio_cmd_write(struct hns_mdio_device *mdio_dev, u8 is_c45, u8 op, u8 phy_id, u16 cmd)
{
u32 cmd_reg_value;
u8 st = is_c45 ? MDIO_ST_CLAUSE_45 : MDIO_ST_CLAUSE_22;
cmd_reg_value = st << MDIO_CMD_ST_S;
cmd_reg_value |= op << MDIO_CMD_OP_S;
cmd_reg_value |= (phy_id & MDIO_CMD_PRTAD_M) << MDIO_CMD_PRTAD_S;
cmd_reg_value |= (cmd & MDIO_CMD_DEVAD_M) << MDIO_CMD_DEVAD_S;
cmd_reg_value |= 1 << MDIO_CMD_START_B;
MDIO_WRITE_REG(mdio_dev, MDIO_COMMAND_REG, cmd_reg_value);
}
static int hns_mdio_write(struct mii_bus *bus, int phy_id, int regnum, u16 data)
{
int ret;
struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
u8 devad = (((u32)regnum >> 16) & 0x1f);
u8 is_c45 = !!((u32)regnum & MII_ADDR_C45);
u16 reg = (u16)((u32)regnum & 0xffff);
u8 op;
u16 cmd_reg_cfg;
/* wait for ready */
ret = hns_mdio_wait_ready(bus);
if (ret != 0) {
printk(KERN_ERR "MDIO bus is busy\n");
return ret;
}
if (!is_c45) {
cmd_reg_cfg = reg;
op = MDIO_C22_WRITE;
} else {
MDIO_SET_REG_FIELD(mdio_dev, MDIO_ADDR_REG, MDIO_ADDR_DATA_M, MDIO_ADDR_DATA_S, reg);
hns_mdio_cmd_write(mdio_dev, is_c45, MDIO_C45_WRITE_ADDR, phy_id, devad);
/* check for read or write opt is finished */
ret = hns_mdio_wait_ready(bus);
if (ret != 0) {
printk(KERN_ERR "MDIO bus is busy\n");
return ret;
}
/* config the data needed writing */
cmd_reg_cfg = devad;
op = MDIO_C45_WRITE_ADDR;
}
MDIO_SET_REG_FIELD(mdio_dev, MDIO_WDATA_REG, MDIO_WDATA_DATA_M, MDIO_WDATA_DATA_S, data);
hns_mdio_cmd_write(mdio_dev, is_c45, op, phy_id, cmd_reg_cfg);
return 0;
}
static int hns_mdio_read(struct mii_bus *bus, int phy_id, int regnum)
{
int ret;
u16 reg_val;
u8 devad = (((u32)regnum >> 16) & 0x1f);
u8 is_c45 = !!((u32)regnum & MII_ADDR_C45);
u16 reg = (u16)((u32)regnum & 0xffff);
struct hns_mdio_device *mdio_dev = (struct hns_mdio_device *)bus->priv;
/* Step 1: wait for ready */
ret = hns_mdio_wait_ready(bus);
if (ret != 0) {
printk(KERN_ERR "MDIO bus is busy\n");
return ret;
}
if (!is_c45) {
hns_mdio_cmd_write(mdio_dev, is_c45, MDIO_C22_READ, phy_id, reg);
} else {
MDIO_SET_REG_FIELD(mdio_dev, MDIO_ADDR_REG, MDIO_ADDR_DATA_M, MDIO_ADDR_DATA_S, reg);
/* Step 2; config the cmd-reg to write addr */
hns_mdio_cmd_write(mdio_dev, is_c45, MDIO_C45_WRITE_ADDR, phy_id, devad);
/* Step 3: check for read or write opt is finished */
ret = hns_mdio_wait_ready(bus);
if (ret != 0) {
printk(KERN_ERR "MDIO bus is busy\n");
return ret;
}
hns_mdio_cmd_write(mdio_dev, is_c45, MDIO_C45_WRITE_ADDR, phy_id, devad);
}
/* Step 5: waitting for MDIO_COMMAND_REG 's mdio_start==0, */
/* check for read or write opt is finished */
ret = hns_mdio_wait_ready(bus);
if (ret != 0) {
printk(KERN_ERR "MDIO bus is busy\n");
return ret;
}
reg_val = MDIO_GET_REG_BIT(mdio_dev, MDIO_STA_REG, MDIO_STATE_STA_B);
if (reg_val != 0) {
printk(KERN_ERR "ERROR! MDIO Read failed!\n");
return -EBUSY;
}
/* Step 6; get out data */
reg_val = (u16)MDIO_GET_REG_FIELD(mdio_dev, MDIO_RDATA_REG, MDIO_RDATA_DATA_M, MDIO_RDATA_DATA_S);
return reg_val;
}
/* *
* hns_mdio_bus_name - get mdio bus name
* @name: mdio bus name
* @np: mdio device node pointer
*/
static void hns_mdio_bus_name(char *name, struct device_node *np)
{
const u32 *addr = NULL;
u64 taddr = OF_BAD_ADDR;
int ret;
addr = of_get_address(np, 0, NULL, NULL);
if (addr != NULL) {
taddr = of_translate_address(np, addr);
}
ret = snprintf_s(name, MII_BUS_ID_SIZE, MII_BUS_ID_SIZE - 1, "%s@%llx", np->name, (unsigned long long)taddr);
if (ret > 0) {
printk(KERN_INFO "get bus name suceess\n");
}
}
static int mdio_open(struct inode *node, struct file *file)
{
struct hns_mdio_device *mdio_dev;
mdio_dev = container_of(node->i_cdev, struct hns_mdio_device, mdio_cdev);
file->private_data = (void *)mdio_dev;
return 0;
}
static int mdio_release(struct inode *node, struct file *file)
{
file->private_data = NULL;
return 0;
}
static long mdio_ioctl(struct file *file, unsigned int cmd, unsigned long arg)
{
return 0;
}
static const struct file_operations mdio_ops = {
.owner = THIS_MODULE,
.open = mdio_open,
.release = mdio_release,
.unlocked_ioctl = mdio_ioctl,
};
static int hns_mdio_cdev_create(struct hns_mdio_device *mdio_dev)
{
struct device *drv_dev = NULL;
int ret;
ret = alloc_chrdev_region(&mdio_dev->mdio_devno, 0, MDIO_CDEV_MINORS, MDIO_CDEV_NAME);
if (ret != 0) {
printk(KERN_ERR "alloc_chrdev_region failed, ret = %d\n", ret);
goto _out;
}
mdio_dev->mdio_cdev_cls = class_create(THIS_MODULE, MDIO_CDEV_NAME);
if (IS_ERR(mdio_dev->mdio_cdev_cls)) {
printk(KERN_ERR "class_create faild, ret = %pK\n", mdio_dev->mdio_cdev_cls);
goto _unregister_region;
}
drv_dev = device_create(mdio_dev->mdio_cdev_cls, NULL, mdio_dev->mdio_devno, NULL, MDIO_CDEV_NAME);
if (IS_ERR(drv_dev)) {
printk(KERN_ERR "failed to create device, ret = %ld\n", PTR_ERR(drv_dev));
goto _class_del;
}
cdev_init(&mdio_dev->mdio_cdev, &mdio_ops);
mdio_dev->mdio_cdev.owner = THIS_MODULE;
ret = cdev_add(&mdio_dev->mdio_cdev, mdio_dev->mdio_devno, MDIO_CDEV_MINORS);
if (ret != 0) {
printk(KERN_ERR "cdev_add failed, ret = %d\n", ret);
goto _device_del;
}
printk(KERN_INFO "mdio cdev create finish, name is %s\n", MDIO_CDEV_NAME);
return 0;
_device_del:
device_destroy(mdio_dev->mdio_cdev_cls, mdio_dev->mdio_devno);
_class_del:
class_destroy(mdio_dev->mdio_cdev_cls);
_unregister_region:
unregister_chrdev_region(mdio_dev->mdio_devno, MDIO_CDEV_MINORS);
_out:
return -EINVAL;
}
int hns_mdio_cdev_del(struct hns_mdio_device *mdio_dev)
{
cdev_del(&mdio_dev->mdio_cdev);
device_destroy(mdio_dev->mdio_cdev_cls, mdio_dev->mdio_devno);
class_destroy(mdio_dev->mdio_cdev_cls);
unregister_chrdev_region(mdio_dev->mdio_devno, MDIO_CDEV_MINORS);
mdio_dev->mdio_cdev_cls = NULL;
printk(KERN_INFO "mdio cdev del finish\n");
return 0;
}
static const struct peri_sc_mdio_reg hi1911_peri_sc_mdio_reg = {
.mdio_clk_en = 0x320,
.mdio_clk_dis = 0x324,
.mdio_reset_req = 0x418,
.mdio_reset_dreq = 0x41C,
.mdio_ctrl = 0,
.mdio_clk_st = 0x5320,
.mdio_reset_st = 0x5418,
};
static const struct of_device_id hns_mdio_match[] = {
{
.compatible = "hisilicon,hi1910b-mdio",
.data = &hi1911_peri_sc_mdio_reg
},
{ }
};
MODULE_DEVICE_TABLE(of, hns_mdio_match);
static int hns_mdiobus_register(struct device_node *np, struct mii_bus *new_bus, int *no_phy)
{
int ret;
ret = of_mdiobus_register(new_bus, np);
if (ret != 0) {
printk(KERN_ERR "Cannot register as MDIO bus!\n");
return ret;
}
return ret;
}
static int hns_mdio_bus_info_init(struct platform_device *pdev,
struct hns_mdio_device *mdio_dev, struct mii_bus *new_bus, struct device_node *np)
{
int ret;
int no_phy = 0;
struct resource *res = NULL;
new_bus->name = MDIO_BUS_NAME;
new_bus->read = hns_mdio_read;
new_bus->write = hns_mdio_write;
new_bus->priv = mdio_dev;
hns_mdio_bus_name(new_bus->id, np);
res = platform_get_resource(pdev, IORESOURCE_MEM, MEM_MDIO_IOBASE);
mdio_dev->vbase = devm_ioremap_resource(&pdev->dev, res);
if (IS_ERR(mdio_dev->vbase)) {
ret = PTR_ERR(mdio_dev->vbase);
return ret;
}
res = platform_get_resource(pdev, IORESOURCE_MEM, MEM_SYSCTRL_IOBASE);
mdio_dev->subctrl_vbase = devm_ioremap(&pdev->dev, res->start, resource_size(res));
if (IS_ERR(mdio_dev->subctrl_vbase)) {
ret = PTR_ERR(mdio_dev->subctrl_vbase);
return ret;
}
#if LINUX_VERSION_CODE >= KERNEL_VERSION(4, 5, 0)
#else
new_bus->irq = devm_kcalloc(&pdev->dev, PHY_MAX_ADDR, sizeof(int), GFP_KERNEL);
if (!new_bus->irq) {
return -ENOMEM;
}
#endif
new_bus->parent = &pdev->dev;
platform_set_drvdata(pdev, new_bus);
hns_mdiobus = new_bus;
ret = hns_mdiobus_register(np, new_bus, &no_phy);
if (ret != 0) {
platform_set_drvdata(pdev, NULL);
return ret;
}
ret = hns_mdio_cdev_create(mdio_dev);
if (ret != 0) {
printk(KERN_ERR "hns_mdio_cdev_create failed\n");
if (!no_phy) {
mdiobus_unregister(new_bus);
}
platform_set_drvdata(pdev, NULL);
}
return 0;
}
static void hhns_mdio_test(struct mii_bus *bus)
{
u16 phy_id_1;
u16 phy_id_2;
u16 value;
int ret;
printk(KERN_INFO "Now let's test the mdio function.");
ret = hns_mdio_read(bus, 0x1, 0x2);
if (ret < 0) {
printk(KERN_ERR "Function hns_mdio_read phy addr 0x1, reg 0x2 failed.");
return;
}
phy_id_1 = (u16)ret;
ret = hns_mdio_read(bus, 0x1, 0x3);
if (ret < 0) {
printk(KERN_ERR "Function hns_mdio_read phy addr 0x1, reg 0x3 failed.");
return;
}
phy_id_2 = (u16)ret;
printk(KERN_INFO "Now get phy addr 0x1, reg 0x2 value [0x%x].", phy_id_1);
printk(KERN_INFO "Now get phy addr 0x1, reg 0x3 value [0x%x].", phy_id_2);
ret = hns_mdio_read(bus, 0x1, 0x0);
if (ret < 0) {
printk(KERN_ERR "Function hns_mdio_read phy addr 0x1, reg 0x0 failed.");
return;
}
value = (u16)ret;
printk(KERN_INFO "Now get phy addr 0x1, reg 0x0 value [0x%x].", value);
value &= 0xFEFF;
ret = hns_mdio_write(bus, 0x1, 0x0, value);
if (ret != 0) {
printk(KERN_ERR "Function hns_mdio_write phy addr 0x1, reg 0x0 failed.");
return;
}
printk(KERN_INFO "Now set phy addr 0x1, reg 0x0 value [0x%x].", value);
ret = hns_mdio_read(bus, 0x1, 0x0);
if (ret < 0) {
printk(KERN_ERR "Function hns_mdio_read phy addr 0x1, reg 0x0 failed.");
return;
}
value = (u16)ret;
printk(KERN_INFO "Now get phy addr 0x1, reg 0x0 value [0x%x].", value);
}
/* *
* hns_mdio_probe - probe mdio device
* @pdev: mdio platform device
*
* Return 0 on success, negative on failure
*/
static int hns_mdio_probe(struct platform_device *pdev)
{
struct device_node *np = NULL;
struct hns_mdio_device *mdio_dev = NULL;
struct mii_bus *new_bus = NULL;
const struct of_device_id *of_id = NULL;
int ret;
if (pdev == NULL) {
printk(KERN_ERR "pdev is NULL!\n");
return -ENODEV;
}
np = pdev->dev.of_node;
mdio_dev = (struct hns_mdio_device *)devm_kzalloc(&pdev->dev, sizeof(struct hns_mdio_device), GFP_KERNEL);
if (mdio_dev == NULL) {
return -ENOMEM;
}
new_bus = devm_mdiobus_alloc(&pdev->dev);
if (new_bus == NULL) {
printk(KERN_ERR "mdiobus_alloc fail!\n");
return -ENOMEM;
}
of_id = of_match_device(hns_mdio_match, &pdev->dev);
if (of_id == NULL) {
return -ENODEV;
}
mdio_dev->sc_reg = of_id->data;
ret = hns_mdio_bus_info_init(pdev, mdio_dev, new_bus, np);
if (ret != 0) {
printk(KERN_ERR "hns_mdio_bus_info_init failed.(ret=%d)", ret);
return ret;
}
hhns_mdio_test(new_bus);
return 0;
}
static int hns_mdio_remove(struct platform_device *pdev)
{
struct hns_mdio_device *mdio_dev = NULL;
struct mii_bus *bus = NULL;
bus = platform_get_drvdata(pdev);
if (bus == NULL) {
printk(KERN_ERR "bus is NULL");
return -EINVAL;
}
mdio_dev = (struct hns_mdio_device *)bus->priv;
if (mdio_dev == NULL) {
printk(KERN_ERR "mdio_dev is NULL");
return -EINVAL;
}
mdiobus_unregister(bus);
platform_set_drvdata(pdev, NULL);
hns_mdio_cdev_del(mdio_dev);
printk(KERN_INFO "mdio remove finish\n");
return 0;
}
static struct platform_driver hns_mdio_driver = {
.remove = hns_mdio_remove,
.probe = hns_mdio_probe,
.driver = {
.of_match_table = hns_mdio_match,
.name = MDIO_DRV_NAME,
},
};
module_platform_driver(hns_mdio_driver);
MODULE_LICENSE("GPL");
MODULE_ALIAS("platform:" MDIO_DRV_NAME);
MODULE_DESCRIPTION("Hisilicon HNS MDIO Daemo driver");
添加如下代码,配置完成后,按“Esc”键,再执行:wq!保存修改,并按“Enter”键退出。
直接拷贝文档中代码到Linux系统中使用可能有格式不兼容问题,例如空格与Tab键使用错误,若出现类似报错,请先在Linux系统中调整代码格式正确。
ccflags-y += -Wall -Werror -Wtrampolines $(WDATE_TIME) -Wfloat-equal -Wvla -Wundef -funsigned-char -Wformat=2 -Wstack-usage=2048 -Wcast-align
ccflags-y += -Wextra -Wno-unused-parameter -Wno-sign-compare -Wno-missing-field-initializers
obj-m += hns_mdio_daemo.o
hns_mdio_daemo-objs := hns_mdio.o
.PHONY : clean
clean :
rm -fr Module.symvers ; rm -fr Module.markers ; rm -fr modules.order
rm -fr *.mod.c *.mod *.o .*.cmd *.ko *~
rm -fr .tmp_versions
添加如下代码,配置完成后,按“Esc”键,再执行:wq!保存修改,并按“Enter”键退出。
LOCAL_PATH := $(call my-dir) include $(CLEAR_VARS) LOCAL_MODULE := hns_mdio_daemo LOCAL_KO_SRC_FOLDER := $(LOCAL_PATH) LOCAL_INSTALLED_KO_FILES := hns_mdio_daemo.ko include $(BUILD_DEVICE_KO)
make -C /opt/Ascend310B-source/driver/kernel/linux-4.19 ARCH=arm64 M=`pwd` modules CROSS_COMPILE=aarch64-target-linux-gnu-
类似回显信息如下。
make: Entering directory '/opt/Ascend310B-source/driver/kernel/linux-4.19'
CC [M] /opt/Ascend310B-source/driver/drivers/usr/hns_mdio.o
LD [M] /opt/Ascend310B-source/driver/drivers/usr/hns_mdio_daemo.o
WARNING: Symbol version dump "Mr'mrmodule.symvers" is missing.
Modules may not have dependencies or modversions.
MODPOST /opt/Ascend310B-source/driver/drivers/usr/Module.symvers
WARNING: modpost: Symbol info of vmlinux is missing. Unresolved symbol check will be entirely skipped.
CC [M] /opt/Ascend310B-source/driver/drivers/usr/hns_mdio_daemo.mod.o
LD [M] /opt/Ascend310B-source/driver/drivers/usr/hns_mdio_daemo.ko
make: Leaving directory '/opt/Ascend310B-source/driver/kernel/linux-4.19'
cd /run
insmod hns_mdio_daemo.ko
hns_mdio_daemo 16384 0