Driver implementation of the BUS protocol abstraction, which is used for the Control and Data communication with the Infineon's WLAN Device. Signed-off-by: Gokul Sivakumar --- drivers/net/wireless/infineon/inffmac/proto.c | 71 +++++++ drivers/net/wireless/infineon/inffmac/proto.h | 192 ++++++++++++++++++ 2 files changed, 263 insertions(+) create mode 100644 drivers/net/wireless/infineon/inffmac/proto.c create mode 100644 drivers/net/wireless/infineon/inffmac/proto.h diff --git a/drivers/net/wireless/infineon/inffmac/proto.c b/drivers/net/wireless/infineon/inffmac/proto.c new file mode 100644 index 000000000000..63f07407dc47 --- /dev/null +++ b/drivers/net/wireless/infineon/inffmac/proto.c @@ -0,0 +1,71 @@ +// SPDX-License-Identifier: ISC +/* + * Copyright (c) 2013 Broadcom Corporation + * + * Copyright (c) 2025, Infineon Technologies AG, or an affiliate of Infineon Technologies AG. + * All rights reserved. + */ + +#include +#include +#include + +#include "core.h" +#include "bus.h" +#include "debug.h" +#include "proto.h" +#include "bcdc.h" +#include "msgbuf.h" + +int inff_proto_attach(struct inff_pub *drvr) +{ + struct inff_proto *proto; + + inff_dbg(TRACE, "Enter\n"); + + proto = kzalloc(sizeof(*proto), GFP_ATOMIC); + if (!proto) + goto fail; + + drvr->proto = proto; + + if (drvr->bus_if->proto_type == INFF_PROTO_BCDC) { + if (inff_proto_bcdc_attach(drvr)) + goto fail; + } else if (drvr->bus_if->proto_type == INFF_PROTO_MSGBUF) { + if (inff_proto_msgbuf_attach(drvr)) + goto fail; + } else { + iphy_err(drvr, "Unsupported proto type %d\n", + drvr->bus_if->proto_type); + goto fail; + } + if (!proto->tx_queue_data || !proto->hdrpull || + !proto->query_dcmd || !proto->set_dcmd || + !proto->configure_addr_mode || + !proto->delete_peer || !proto->add_tdls_peer || + !proto->debugfs_create) { + iphy_err(drvr, "Not all proto handlers have been installed\n"); + goto fail; + } + return 0; + +fail: + kfree(proto); + drvr->proto = NULL; + return -ENOMEM; +} + +void inff_proto_detach(struct inff_pub *drvr) +{ + inff_dbg(TRACE, "Enter\n"); + + if (drvr->proto) { + if (drvr->bus_if->proto_type == INFF_PROTO_BCDC) + inff_proto_bcdc_detach(drvr); + else if (drvr->bus_if->proto_type == INFF_PROTO_MSGBUF) + inff_proto_msgbuf_detach(drvr); + kfree(drvr->proto); + drvr->proto = NULL; + } +} diff --git a/drivers/net/wireless/infineon/inffmac/proto.h b/drivers/net/wireless/infineon/inffmac/proto.h new file mode 100644 index 000000000000..e072c973ec79 --- /dev/null +++ b/drivers/net/wireless/infineon/inffmac/proto.h @@ -0,0 +1,192 @@ +/* SPDX-License-Identifier: ISC */ +/* + * Copyright (c) 2013 Broadcom Corporation + * + * Copyright (c) 2025, Infineon Technologies AG, or an affiliate of Infineon Technologies AG. + * All rights reserved. + */ + +#ifndef INFF_PROTO_H +#define INFF_PROTO_H + +enum proto_addr_mode { + ADDR_INDIRECT = 0, + ADDR_DIRECT +}; + +struct inff_skb_reorder_data { + u8 *reorder; +}; + +struct inff_proto { + int (*hdrpull)(struct inff_pub *drvr, bool do_fws, + struct sk_buff *skb, struct inff_if **ifp); + int (*query_dcmd)(struct inff_pub *drvr, int ifidx, uint cmd, + void *buf, uint len, int *fwerr); + int (*set_dcmd)(struct inff_pub *drvr, int ifidx, uint cmd, void *buf, + uint len, int *fwerr); + int (*tx_queue_data)(struct inff_pub *drvr, int ifidx, + struct sk_buff *skb); + int (*txdata)(struct inff_pub *drvr, int ifidx, u8 offset, + struct sk_buff *skb); + void (*configure_addr_mode)(struct inff_pub *drvr, int ifidx, + enum proto_addr_mode addr_mode); + void (*delete_peer)(struct inff_pub *drvr, int ifidx, + u8 peer[ETH_ALEN]); + void (*add_tdls_peer)(struct inff_pub *drvr, int ifidx, + u8 peer[ETH_ALEN]); + void (*rxreorder)(struct inff_if *ifp, struct sk_buff *skb, bool inirq); + void (*add_if)(struct inff_if *ifp); + void (*del_if)(struct inff_if *ifp); + void (*reset_if)(struct inff_if *ifp); + void (*cleanup_if)(struct inff_if *ifp); + int (*init_done)(struct inff_pub *drvr); + void (*debugfs_create)(struct inff_pub *drvr); + int (*xdp_init)(struct inff_pub *drvr, struct inff_if *ifp); + void (*xdp_deinit)(struct inff_pub *drvr); + void *pd; +}; + +int inff_proto_attach(struct inff_pub *drvr); +void inff_proto_detach(struct inff_pub *drvr); + +static inline int inff_proto_hdrpull(struct inff_pub *drvr, bool do_fws, + struct sk_buff *skb, + struct inff_if **ifp) +{ + struct inff_if *tmp = NULL; + + /* assure protocol is always called with + * non-null initialized pointer. + */ + if (ifp) + *ifp = NULL; + else + ifp = &tmp; + return drvr->proto->hdrpull(drvr, do_fws, skb, ifp); +} + +static inline int inff_proto_query_dcmd(struct inff_pub *drvr, int ifidx, + uint cmd, void *buf, uint len, + int *fwerr) +{ + return drvr->proto->query_dcmd(drvr, ifidx, cmd, buf, len, fwerr); +} + +static inline int inff_proto_set_dcmd(struct inff_pub *drvr, int ifidx, + uint cmd, void *buf, uint len, + int *fwerr) +{ + return drvr->proto->set_dcmd(drvr, ifidx, cmd, buf, len, fwerr); +} + +static inline int inff_proto_tx_queue_data(struct inff_pub *drvr, int ifidx, + struct sk_buff *skb) +{ + return drvr->proto->tx_queue_data(drvr, ifidx, skb); +} + +static inline int inff_proto_txdata(struct inff_pub *drvr, int ifidx, + u8 offset, struct sk_buff *skb) +{ + return drvr->proto->txdata(drvr, ifidx, offset, skb); +} + +static inline void +inff_proto_configure_addr_mode(struct inff_pub *drvr, int ifidx, + enum proto_addr_mode addr_mode) +{ + drvr->proto->configure_addr_mode(drvr, ifidx, addr_mode); +} + +static inline void +inff_proto_delete_peer(struct inff_pub *drvr, int ifidx, u8 peer[ETH_ALEN]) +{ + drvr->proto->delete_peer(drvr, ifidx, peer); +} + +static inline void +inff_proto_add_tdls_peer(struct inff_pub *drvr, int ifidx, u8 peer[ETH_ALEN]) +{ + drvr->proto->add_tdls_peer(drvr, ifidx, peer); +} + +static inline bool inff_proto_is_reorder_skb(struct sk_buff *skb) +{ + struct inff_skb_reorder_data *rd; + + rd = (struct inff_skb_reorder_data *)skb->cb; + return !!rd->reorder; +} + +static inline void +inff_proto_rxreorder(struct inff_if *ifp, struct sk_buff *skb, bool inirq) +{ + ifp->drvr->proto->rxreorder(ifp, skb, inirq); +} + +static inline void +inff_proto_add_if(struct inff_pub *drvr, struct inff_if *ifp) +{ + if (!drvr->proto->add_if) + return; + drvr->proto->add_if(ifp); +} + +static inline void +inff_proto_del_if(struct inff_pub *drvr, struct inff_if *ifp) +{ + if (!drvr->proto->del_if) + return; + drvr->proto->del_if(ifp); +} + +static inline void +inff_proto_reset_if(struct inff_pub *drvr, struct inff_if *ifp) +{ + if (!drvr->proto->reset_if) + return; + drvr->proto->reset_if(ifp); +} + +static inline void +inff_proto_cleanup_if(struct inff_pub *drvr, struct inff_if *ifp) +{ + if (!drvr->proto->cleanup_if) + return; + drvr->proto->cleanup_if(ifp); +} + +static inline int +inff_proto_init_done(struct inff_pub *drvr) +{ + if (!drvr->proto->init_done) + return 0; + return drvr->proto->init_done(drvr); +} + +static inline void +inff_proto_debugfs_create(struct inff_pub *drvr) +{ + drvr->proto->debugfs_create(drvr); +} + +static inline int +inff_proto_xdp_init(struct inff_pub *drvr, struct inff_if *ifp) +{ + if (!drvr->proto || + !drvr->proto->xdp_init) + return 0; + return drvr->proto->xdp_init(drvr, ifp); +} + +static inline void +inff_proto_xdp_deinit(struct inff_pub *drvr) +{ + if (!drvr->proto || + !drvr->proto->xdp_deinit) + return; + drvr->proto->xdp_deinit(drvr); +} + +#endif /* INFF_PROTO_H */ -- 2.25.1