Message ID | 20230830110847.1219515-2-danishanwar@ti.com (mailing list archive) |
---|---|
State | RFC |
Delegated to: | Netdev Maintainers |
Headers | show |
Series | Introduce switch mode and TAPRIO offload support for ICSSG driver | expand |
> +int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd, > + struct mgmt_cmd_rsp *rsp) > +{ > + struct prueth *prueth = emac->prueth; > + int slice = prueth_emac_slice(emac); > + int i = 10000; > + int addr; > + > + addr = icssg_queue_pop(prueth, slice == 0 ? > + ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1); > + if (addr < 0) > + return addr; > + > + /* First 4 bytes have FW owned buffer linking info which should > + * not be touched > + */ > + memcpy_toio(prueth->shram.va + addr + 4, cmd, sizeof(*cmd)); > + icssg_queue_push(prueth, slice == 0 ? > + ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr); > + while (i--) { > + addr = icssg_queue_pop(prueth, slice == 0 ? > + ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1); > + if (addr < 0) { > + usleep_range(1000, 2000); > + continue; > + } Please try to make use of include/linux/iopoll.h. > + if (i <= 0) { > + netdev_err(emac->ndev, "Timedout sending HWQ message\n"); > + return -EINVAL; Using iopoll.h will fix this, but -ETIMEDOUT, not -EINVAL. Andrew
Hi Andrew On 04/09/23 19:32, Andrew Lunn wrote: >> +int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd, >> + struct mgmt_cmd_rsp *rsp) >> +{ >> + struct prueth *prueth = emac->prueth; >> + int slice = prueth_emac_slice(emac); >> + int i = 10000; >> + int addr; >> + >> + addr = icssg_queue_pop(prueth, slice == 0 ? >> + ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1); >> + if (addr < 0) >> + return addr; >> + >> + /* First 4 bytes have FW owned buffer linking info which should >> + * not be touched >> + */ >> + memcpy_toio(prueth->shram.va + addr + 4, cmd, sizeof(*cmd)); >> + icssg_queue_push(prueth, slice == 0 ? >> + ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr); >> + while (i--) { >> + addr = icssg_queue_pop(prueth, slice == 0 ? >> + ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1); >> + if (addr < 0) { >> + usleep_range(1000, 2000); >> + continue; >> + } > > Please try to make use of include/linux/iopoll.h. > I don't think APIs from iopoll.h will be useful here. readl_poll_timeout() periodically polls an address until a condition is met or a timeout occurs. It takes address, condition as argument and store the value read from the address in val. Here in our use case we need to continuously read the value returned from icssg_queue_pop() and check if that is valid or not. If it's not valid, we keep polling until timeout happens. icssg_queue_pop() does two read operations. It checks if the queue number is valid or not. Then it reads the ICSSG_QUEUE_CNT_OFFSET for that queue, if the value read is zero it returns inval. After that it reads the value from ICSSG_QUEUE_OFFSET of that queue and store it in 'val'. The returned value from icssg_queue_pop() is checked continuously, if it's an error code, we keep polling. If it's a good value then we call icssg_queue_push() with that value. As you can see from the below definition of icssg_queue_pop() we are doing two reads and two checks for error. I don't think this can be achieved by using APIs in iopoll.h. readl_poll_timeout() reads from a single address directly but we don't ave a single address that we can pass to readl_poll_timeout() as an argument as we have to do two reads from two different addresses during each poll. So I don't think we can use iopoll.h here. Please let me know if this looks ok to you or if there is any other way we can use iopoll.h here int icssg_queue_pop(struct prueth *prueth, u8 queue) { u32 val, cnt; if (queue >= ICSSG_QUEUES_MAX) return -EINVAL; regmap_read(prueth->miig_rt, ICSSG_QUEUE_CNT_OFFSET + 4*queue,&cnt); if (!cnt) return -EINVAL; regmap_read(prueth->miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue, &val); return val; } >> + if (i <= 0) { >> + netdev_err(emac->ndev, "Timedout sending HWQ message\n"); >> + return -EINVAL; > > Using iopoll.h will fix this, but -ETIMEDOUT, not -EINVAL. > -ETIMEDOUT is actually a better suited error code here, I will change -EINVAL to -ETIMEDOUT in this if check. > Andrew >
On 05/09/2023 11:36, MD Danish Anwar wrote: > Hi Andrew > > On 04/09/23 19:32, Andrew Lunn wrote: >>> +int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd, >>> + struct mgmt_cmd_rsp *rsp) >>> +{ >>> + struct prueth *prueth = emac->prueth; >>> + int slice = prueth_emac_slice(emac); >>> + int i = 10000; >>> + int addr; >>> + >>> + addr = icssg_queue_pop(prueth, slice == 0 ? >>> + ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1); >>> + if (addr < 0) >>> + return addr; >>> + >>> + /* First 4 bytes have FW owned buffer linking info which should >>> + * not be touched >>> + */ >>> + memcpy_toio(prueth->shram.va + addr + 4, cmd, sizeof(*cmd)); >>> + icssg_queue_push(prueth, slice == 0 ? >>> + ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr); >>> + while (i--) { >>> + addr = icssg_queue_pop(prueth, slice == 0 ? >>> + ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1); >>> + if (addr < 0) { >>> + usleep_range(1000, 2000); >>> + continue; >>> + } >> >> Please try to make use of include/linux/iopoll.h. >> > > I don't think APIs from iopoll.h will be useful here. > readl_poll_timeout() periodically polls an address until a condition is > met or a timeout occurs. It takes address, condition as argument and > store the value read from the address in val. You need to use read_poll_timeout() and provide the read function as first argument 'op'. The arguments to the read function can be passed as is at the end. Please read description of read_poll_timeout() > > Here in our use case we need to continuously read the value returned > from icssg_queue_pop() and check if that is valid or not. If it's not > valid, we keep polling until timeout happens. > > icssg_queue_pop() does two read operations. It checks if the queue > number is valid or not. Then it reads the ICSSG_QUEUE_CNT_OFFSET for > that queue, if the value read is zero it returns inval. After that it > reads the value from ICSSG_QUEUE_OFFSET of that queue and store it in > 'val'. The returned value from icssg_queue_pop() is checked > continuously, if it's an error code, we keep polling. If it's a good > value then we call icssg_queue_push() with that value. As you can see > from the below definition of icssg_queue_pop() we are doing two reads > and two checks for error. I don't think this can be achieved by using > APIs in iopoll.h. readl_poll_timeout() reads from a single address > directly but we don't ave a single address that we can pass to > readl_poll_timeout() as an argument as we have to do two reads from two > different addresses during each poll. > > So I don't think we can use iopoll.h here. Please let me know if this > looks ok to you or if there is any other way we can use iopoll.h here > > int icssg_queue_pop(struct prueth *prueth, u8 queue) > { > u32 val, cnt; > > if (queue >= ICSSG_QUEUES_MAX) > return -EINVAL; > > regmap_read(prueth->miig_rt, ICSSG_QUEUE_CNT_OFFSET + 4*queue,&cnt); > if (!cnt) > return -EINVAL; > > regmap_read(prueth->miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue, &val); > > return val; > } > >>> + if (i <= 0) { >>> + netdev_err(emac->ndev, "Timedout sending HWQ message\n"); >>> + return -EINVAL; >> >> Using iopoll.h will fix this, but -ETIMEDOUT, not -EINVAL. >> > > -ETIMEDOUT is actually a better suited error code here, I will change > -EINVAL to -ETIMEDOUT in this if check. > >> Andrew >> >
On 07/09/23 17:27, Roger Quadros wrote: > > > On 05/09/2023 11:36, MD Danish Anwar wrote: >> Hi Andrew >> >> On 04/09/23 19:32, Andrew Lunn wrote: >>>> +int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd, >>>> + struct mgmt_cmd_rsp *rsp) >>>> +{ >>>> + struct prueth *prueth = emac->prueth; >>>> + int slice = prueth_emac_slice(emac); >>>> + int i = 10000; >>>> + int addr; >>>> + >>>> + addr = icssg_queue_pop(prueth, slice == 0 ? >>>> + ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1); >>>> + if (addr < 0) >>>> + return addr; >>>> + >>>> + /* First 4 bytes have FW owned buffer linking info which should >>>> + * not be touched >>>> + */ >>>> + memcpy_toio(prueth->shram.va + addr + 4, cmd, sizeof(*cmd)); >>>> + icssg_queue_push(prueth, slice == 0 ? >>>> + ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr); >>>> + while (i--) { >>>> + addr = icssg_queue_pop(prueth, slice == 0 ? >>>> + ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1); >>>> + if (addr < 0) { >>>> + usleep_range(1000, 2000); >>>> + continue; >>>> + } >>> >>> Please try to make use of include/linux/iopoll.h. >>> >> >> I don't think APIs from iopoll.h will be useful here. >> readl_poll_timeout() periodically polls an address until a condition is >> met or a timeout occurs. It takes address, condition as argument and >> store the value read from the address in val. > > You need to use read_poll_timeout() and provide the read function as > first argument 'op'. The arguments to the read function can be passed as is > at the end. Please read description of read_poll_timeout() > I was only looking into real/b/w_poll_timeout() as it is mentioned in iopoll.h to not use read_poll_timeout() directly. Anyways, I will use read_poll_timeout() here with icssg_pop_queue() as a read API. >> >> Here in our use case we need to continuously read the value returned >> from icssg_queue_pop() and check if that is valid or not. If it's not >> valid, we keep polling until timeout happens. >> >> icssg_queue_pop() does two read operations. It checks if the queue >> number is valid or not. Then it reads the ICSSG_QUEUE_CNT_OFFSET for >> that queue, if the value read is zero it returns inval. After that it >> reads the value from ICSSG_QUEUE_OFFSET of that queue and store it in >> 'val'. The returned value from icssg_queue_pop() is checked >> continuously, if it's an error code, we keep polling. If it's a good >> value then we call icssg_queue_push() with that value. As you can see >> from the below definition of icssg_queue_pop() we are doing two reads >> and two checks for error. I don't think this can be achieved by using >> APIs in iopoll.h. readl_poll_timeout() reads from a single address >> directly but we don't ave a single address that we can pass to >> readl_poll_timeout() as an argument as we have to do two reads from two >> different addresses during each poll. >> >> So I don't think we can use iopoll.h here. Please let me know if this >> looks ok to you or if there is any other way we can use iopoll.h here >> >> int icssg_queue_pop(struct prueth *prueth, u8 queue) >> { >> u32 val, cnt; >> >> if (queue >= ICSSG_QUEUES_MAX) >> return -EINVAL; >> >> regmap_read(prueth->miig_rt, ICSSG_QUEUE_CNT_OFFSET + 4*queue,&cnt); >> if (!cnt) >> return -EINVAL; >> >> regmap_read(prueth->miig_rt, ICSSG_QUEUE_OFFSET + 4 * queue, &val); >> >> return val; >> } >> >>>> + if (i <= 0) { >>>> + netdev_err(emac->ndev, "Timedout sending HWQ message\n"); >>>> + return -EINVAL; >>> >>> Using iopoll.h will fix this, but -ETIMEDOUT, not -EINVAL. >>> >> >> -ETIMEDOUT is actually a better suited error code here, I will change >> -EINVAL to -ETIMEDOUT in this if check. >> >>> Andrew >>> >> >
diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.c b/drivers/net/ethernet/ti/icssg/icssg_config.c index 933b84666574..3fccdcc20bdb 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_config.c +++ b/drivers/net/ethernet/ti/icssg/icssg_config.c @@ -455,3 +455,198 @@ void icssg_config_set_speed(struct prueth_emac *emac) writeb(fw_speed, emac->dram.va + PORT_LINK_SPEED_OFFSET); } + +int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd, + struct mgmt_cmd_rsp *rsp) +{ + struct prueth *prueth = emac->prueth; + int slice = prueth_emac_slice(emac); + int i = 10000; + int addr; + + addr = icssg_queue_pop(prueth, slice == 0 ? + ICSSG_CMD_POP_SLICE0 : ICSSG_CMD_POP_SLICE1); + if (addr < 0) + return addr; + + /* First 4 bytes have FW owned buffer linking info which should + * not be touched + */ + memcpy_toio(prueth->shram.va + addr + 4, cmd, sizeof(*cmd)); + icssg_queue_push(prueth, slice == 0 ? + ICSSG_CMD_PUSH_SLICE0 : ICSSG_CMD_PUSH_SLICE1, addr); + while (i--) { + addr = icssg_queue_pop(prueth, slice == 0 ? + ICSSG_RSP_POP_SLICE0 : ICSSG_RSP_POP_SLICE1); + if (addr < 0) { + usleep_range(1000, 2000); + continue; + } + + memcpy_fromio(rsp, prueth->shram.va + addr, sizeof(*rsp)); + /* Return buffer back for to pool */ + icssg_queue_push(prueth, slice == 0 ? + ICSSG_RSP_PUSH_SLICE0 : ICSSG_RSP_PUSH_SLICE1, addr); + break; + } + if (i <= 0) { + netdev_err(emac->ndev, "Timedout sending HWQ message\n"); + return -EINVAL; + } + + return 0; +} + +int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr, + u8 vid, u8 fid_c2, bool add) +{ + struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 }; + int slice = prueth_emac_slice(emac); + struct mgmt_cmd fdb_cmd = { 0 }; + u8 mac_fid[ETH_ALEN + 2]; + u16 fdb_slot; + u8 fid = vid; + int ret, i; + + for (i = 0; i < ETH_ALEN; i++) + mac_fid[i] = addr[i]; + + /* 1-1 VID-FID mapping is already setup */ + mac_fid[ETH_ALEN] = fid; + mac_fid[ETH_ALEN + 1] = 0; + + fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK; + + fdb_cmd.header = ICSSG_FW_MGMT_CMD_HEADER; + fdb_cmd.type = ICSSG_FW_MGMT_FDB_CMD_TYPE; + fdb_cmd.seqnum = ++(emac->prueth->icssg_hwcmdseq); + if (add) + fdb_cmd.param = ICSS_CMD_ADD_FDB; + else + fdb_cmd.param = ICSS_CMD_DEL_FDB; + + fdb_cmd.param |= (slice << 4); + + fid_c2 |= ICSSG_FDB_ENTRY_VALID; + memcpy(&fdb_cmd.cmd_args[0], addr, 4); + memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2); + fdb_cmd.cmd_args[1] |= ((fid << 16) | (fid_c2 << 24)); + fdb_cmd.cmd_args[2] = fdb_slot; + + netdev_dbg(emac->ndev, "MAC %pM slot %X vlan %X FID %X\n", + addr, fdb_slot, vid, fid); + + ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp); + if (ret) + return ret; + + WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum); + if (fdb_cmd_rsp.status == 1) + return 0; + + return -EINVAL; +} + +int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr, + u8 vid) +{ + struct mgmt_cmd_rsp fdb_cmd_rsp = { 0 }; + int slice = prueth_emac_slice(emac); + struct mgmt_cmd fdb_cmd = { 0 }; + struct prueth_fdb_slot *slot; + u8 mac_fid[ETH_ALEN + 2]; + u16 fdb_slot; + u8 fid = vid; + int ret, i; + + for (i = 0; i < ETH_ALEN; i++) + mac_fid[i] = addr[i]; + + /* 1-1 VID-FID mapping is already setup */ + mac_fid[ETH_ALEN] = fid; + mac_fid[ETH_ALEN + 1] = 0; + + fdb_slot = bitrev32(crc32_le(0, mac_fid, 8)) & PRUETH_SWITCH_FDB_MASK; + + fdb_cmd.header = ICSSG_FW_MGMT_CMD_HEADER; + fdb_cmd.type = ICSSG_FW_MGMT_FDB_CMD_TYPE; + fdb_cmd.seqnum = ++(emac->prueth->icssg_hwcmdseq); + fdb_cmd.param = ICSS_CMD_GET_FDB_SLOT; + + fdb_cmd.param |= (slice << 4); + + memcpy(&fdb_cmd.cmd_args[0], addr, 4); + memcpy(&fdb_cmd.cmd_args[1], &addr[4], 2); + fdb_cmd.cmd_args[1] |= fid << 16; + fdb_cmd.cmd_args[2] = fdb_slot; + + ret = icssg_send_fdb_msg(emac, &fdb_cmd, &fdb_cmd_rsp); + if (ret) + return ret; + + WARN_ON(fdb_cmd.seqnum != fdb_cmd_rsp.seqnum); + + slot = (struct prueth_fdb_slot __force *)emac->dram.va + FDB_CMD_BUFFER; + for (i = 0; i < 4; i++) { + if (ether_addr_equal(addr, slot->mac) && vid == slot->fid) + return (slot->fid_c2 & ~ICSSG_FDB_ENTRY_VALID); + slot++; + } + + return 0; +} + +void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask, + u8 untag_mask, bool add) +{ + struct prueth *prueth = emac->prueth; + struct prueth_vlan_tbl *tbl; + u8 fid_c1; + + tbl = prueth->vlan_tbl; + fid_c1 = tbl[vid].fid_c1; + + /* FID_C1: bit0..2 port membership mask, + * bit3..5 tagging mask for each port + * bit6 Stream VID (not handled currently) + * bit7 MC flood (not handled currently) + */ + if (add) { + fid_c1 |= (port_mask | port_mask << 3); + fid_c1 &= ~(untag_mask << 3); + } else { + fid_c1 &= ~(port_mask | port_mask << 3); + } + + tbl[vid].fid_c1 = fid_c1; +} + +u16 icssg_get_pvid(struct prueth_emac *emac) +{ + struct prueth *prueth = emac->prueth; + u32 pvid; + + if (emac->port_id == PRUETH_PORT_MII0) + pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET); + else + pvid = readl(prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET); + + pvid = pvid >> 24; + + return pvid; +} + +void icssg_set_pvid(struct prueth *prueth, u8 vid, u8 port) +{ + u32 pvid; + + /* only 256 VLANs are supported */ + pvid = (u32 __force)cpu_to_be32((ETH_P_8021Q << 16) | (vid & 0xff)); + + if (port == PRUETH_PORT_MII0) + writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT1_DEFAULT_VLAN_OFFSET); + else if (port == PRUETH_PORT_MII1) + writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT2_DEFAULT_VLAN_OFFSET); + else + writel(pvid, prueth->shram.va + EMAC_ICSSG_SWITCH_PORT0_DEFAULT_VLAN_OFFSET); +} diff --git a/drivers/net/ethernet/ti/icssg/icssg_config.h b/drivers/net/ethernet/ti/icssg/icssg_config.h index 43eb0922172a..0d5d5d253b7a 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_config.h +++ b/drivers/net/ethernet/ti/icssg/icssg_config.h @@ -35,6 +35,8 @@ struct icssg_flow_cfg { (2 * (PRUETH_EMAC_BUF_POOL_SIZE * PRUETH_NUM_BUF_POOLS + \ PRUETH_EMAC_RX_CTX_BUF_SIZE * 2)) +#define PRUETH_SWITCH_FDB_MASK ((SIZE_OF_FDB / NUMBER_OF_FDB_BUCKET_ENTRIES) - 1) + struct icssg_rxq_ctx { __le32 start[3]; __le32 end; @@ -146,6 +148,23 @@ struct icssg_setclock_desc { #define ICSSG_TS_PUSH_SLICE0 40 #define ICSSG_TS_PUSH_SLICE1 41 +struct mgmt_cmd { + u8 param; + u8 seqnum; + u8 type; + u8 header; + u32 cmd_args[3]; +} __packed; + +struct mgmt_cmd_rsp { + u32 reserved; + u8 status; + u8 seqnum; + u8 type; + u8 header; + u32 cmd_args[3]; +} __packed; + /* FDB FID_C2 flag definitions */ /* Indicates host port membership.*/ #define ICSSG_FDB_ENTRY_P0_MEMBERSHIP BIT(0) diff --git a/drivers/net/ethernet/ti/icssg/icssg_prueth.h b/drivers/net/ethernet/ti/icssg/icssg_prueth.h index 3fe80a8758d3..1011917924c8 100644 --- a/drivers/net/ethernet/ti/icssg/icssg_prueth.h +++ b/drivers/net/ethernet/ti/icssg/icssg_prueth.h @@ -209,6 +209,7 @@ struct prueth_pdata { * @emacs_initialized: num of EMACs/ext ports that are up/running * @iep0: pointer to IEP0 device * @iep1: pointer to IEP1 device + * @vlan_tbl: VLAN-FID table pointer */ struct prueth { struct device *dev; @@ -233,6 +234,7 @@ struct prueth { int emacs_initialized; struct icss_iep *iep0; struct icss_iep *iep1; + struct prueth_vlan_tbl *vlan_tbl; }; struct emac_tx_ts_response { @@ -277,6 +279,16 @@ int icssg_queue_pop(struct prueth *prueth, u8 queue); void icssg_queue_push(struct prueth *prueth, int queue, u16 addr); u32 icssg_queue_level(struct prueth *prueth, int queue); +int icssg_send_fdb_msg(struct prueth_emac *emac, struct mgmt_cmd *cmd, + struct mgmt_cmd_rsp *rsp); +int icssg_fdb_add_del(struct prueth_emac *emac, const unsigned char *addr, + u8 vid, u8 fid_c2, bool add); +int icssg_fdb_lookup(struct prueth_emac *emac, const unsigned char *addr, + u8 vid); +void icssg_vtbl_modify(struct prueth_emac *emac, u8 vid, u8 port_mask, + u8 untag_mask, bool add); +u16 icssg_get_pvid(struct prueth_emac *emac); +void icssg_set_pvid(struct prueth *prueth, u8 vid, u8 port); #define prueth_napi_to_tx_chn(pnapi) \ container_of(pnapi, struct prueth_tx_chn, napi_tx)
Introduce helper functions to configure firmware FDB tables, VLAN tables and Port VLAN ID settings to aid adding Switch mode support. Signed-off-by: MD Danish Anwar <danishanwar@ti.com> --- drivers/net/ethernet/ti/icssg/icssg_config.c | 195 +++++++++++++++++++ drivers/net/ethernet/ti/icssg/icssg_config.h | 19 ++ drivers/net/ethernet/ti/icssg/icssg_prueth.h | 12 ++ 3 files changed, 226 insertions(+)