// SPDX-License-Identifier: GPL-2.0 #include "softmac_core.h" #include "utils.h" #include "hal_common.h" #include "img_osal.h" #include "umac_debugs.h" #include "hpqm_if.h" #include "img_module_iface.h" #include "img_host_txrx_buffs.h" #include "img_utils.h" #define RPU_GRAM_BASE 0xB7000000 #define RPU_PERP_BASE_ADDR 0xA5000000 UCC_T *ucc2; HP_T *hostport_ctx3; extern struct lmac_fw_config_params *lmac_fw_config_params_gp; extern unsigned char host_deinit_cmd_rcvd_flag_g; unsigned int RPU_read_word(unsigned int *src) { return UCC_READ32((unsigned int)src); } void RPU_write_word(unsigned int *src , unsigned int data) { UCC_WRITE32((unsigned int)src, data); } void RPU_read_mem(unsigned char *src, unsigned char *dst, unsigned int size) { memcpy(dst, src, size); } unsigned char vif_macs[2][ETH_ALEN]; char *mac_addr; char umac_mac_addr[13]; void tx_tasklet_fn(unsigned long data) { struct hal_priv *priv = (struct hal_priv *)data; unsigned int value = 0; unsigned long start_addr; unsigned long start = 0; struct lmac_msg_hdr *hdr; IRQ_IPL_T old_ipl; struct lst_node *cmd_buff_node = NULL; unsigned int cmd_ptr = 0; unsigned int cmd_ptr_offset = 0; if (priv->hal_disabled) { printk("ERR: priv->hal_disabled: %lu\n", priv->hal_disabled); return; } while ((cmd_buff_node = LST_removeHead(&priv->txq))) { start = jiffies; old_ipl = IRQ_raiseIPL(); cmd_ptr_offset = hpqm_get_cmd_buf_ptr(RPU_PERP_BASE_ADDR, lmac_fw_config_params_gp); if (cmd_ptr_offset == 0) { printk("NO COMMAND PTRS IN BUFFER Q\n"); LST_addHead(&priv->txq, cmd_buff_node); IRQ_restoreIPL(old_ipl); return; } cmd_ptr = RPU_GRAM_BASE + (cmd_ptr_offset & 0xFFFFFF); memcpy((unsigned char *)cmd_ptr, cmd_buff_node->buff, cmd_buff_node->size); IMG_TX_DBG_PARAM_INCR(total_cmds_to_lmac, 1); hpqm_submit_cmd_buf_ptr(hpriv->rpu_sysbus_base, RPU_PERP_BASE_ADDR, cmd_ptr_offset, lmac_fw_config_params_gp); IRQ_restoreIPL(old_ipl); kfree(cmd_buff_node); } } void hal_send(void *msg, void *payload, unsigned int descriptor_id) { LST_add(&hpriv->txq, msg); tx_tasklet_fn((unsigned int)hpriv); } void umac_recover_tx_pending_cmds(); void rx_tasklet_fn(unsigned long event_addr) { struct hal_priv *priv = (struct hal_priv *)hpriv; struct lmac_msg_hdr *evnt; unsigned char *rx_event_info; unsigned int buff_ref[HAL_INT_EVENT_MAX_RX] = {0}; unsigned int ext_addr[HAL_INT_EVENT_MAX_RX]; int alloc_len; struct host_rpu_msg_hdr *hal_hdr = (struct host_rpu_msg_hdr *)event_addr; evnt = (struct lmac_msg_hdr *)(event_addr + sizeof(struct host_rpu_msg_hdr)); if (host_deinit_cmd_rcvd_flag_g == 1){ if (evnt->id != LMAC_EVENT_RESET_COMPLETE) return; } if (evnt->id == LMAC_EVENT_RX) { unsigned int gap,i; struct lmac_event_rx *rx_evnt = (struct lmac_event_rx *)event_addr; IMG_RX_DBG_PARAM_INCR(rx_events, 1); IMG_RX_DBG_PARAM_INCR(total_rx_pkts_from_lmac, rx_evnt->rx_pkt_cnt); IMG_RX_DBG_PARAM_INCR(current_refill_gap, rx_evnt->rx_pkt_cnt); for(i = 0;i < rx_evnt->rx_pkt_cnt;i++) { if (rx_evnt->mpdu_ctrl[i].skb_pointer == 0) { IMG_RX_DBG_PARAM_INCR(null_skb_pointer_from_lmac,1); IMG_RX_DBG_PARAM_DECR(current_refill_gap, 1); } } if (IMG_RX_DBG_PARAM_VAL(current_refill_gap) > IMG_RX_DBG_PARAM_VAL(max_refill_gap)) { IMG_RX_DBG_PARAM_ASSIGN(max_refill_gap, IMG_RX_DBG_PARAM_VAL(current_refill_gap)); } if (rx_evnt->rx_pkt_cnt > 1) { IMG_RX_DBG_PARAM_INCR(rx_coalised_events, 1); if (rx_evnt->rx_pkt_cnt > IMG_RX_DBG_PARAM_VAL(max_coalised_pkts)) IMG_RX_DBG_PARAM_ASSIGN(max_coalised_pkts, rx_evnt->rx_pkt_cnt); } } if (evnt->id == LMAC_EVENT_TX_DONE) { char *msg = malloc(hal_hdr->len); memcpy(msg, (unsigned char *)event_addr, hal_hdr->len); umac_task_post(IMG_MODULE_IFACE_TXDONE_PORT, msg, hal_hdr->len); return; } alloc_len = hal_hdr->len; rx_event_info = malloc(alloc_len); if (rx_event_info == NULL) { pr_err("%s:%d malloc failed\n", __FUNCTION__, __LINE__); return; } memcpy(rx_event_info, (unsigned char *)event_addr, alloc_len); rx_task_post(IMG_MODULE_IFACE_RX_DATA_PORT, rx_event_info, alloc_len); } void hal_irq_handler(unsigned hwStatAddr, unsigned irq, void *p) { (void)hwStatAddr; (void)irq; (void)p; unsigned int value = 0; unsigned int event_addr = 0; unsigned int event_addr_offset = 0; struct hal_priv *priv = hpriv; hpqm_rpu_isr_clear(priv->rpu_sysbus_base, lmac_fw_config_params_gp); while(1) { event_addr_offset = hpqm_get_event_ptr(RPU_PERP_BASE_ADDR, lmac_fw_config_params_gp); if (event_addr_offset != 0) { event_addr = (event_addr_offset & 0xFFFFFF) + RPU_GRAM_BASE; rx_tasklet_fn(event_addr); IMG_RX_DBG_PARAM_INCR(lmac_events, 1); hpqm_free_event_ptr(RPU_PERP_BASE_ADDR, RPU_GRAM_BASE, event_addr_offset); } else { break; } } } void chg_irq_register(void) { /* The API UCCP_getUCC() can be called only after UCCP_init has been called For the LPW case, this is called in the mac_app.c and so we are fine. For the non LPW case, the call to UCCP_init happens within the PHYIF and that is invoked after hal_init. So , we will need to move the call to UCCP_init to mac_app when we merge these changes into the non LPW case */ ucc2 = UCCP_getUCC(1); hostport_ctx3 = UCC_getHostPort(ucc2, 1); /* This core is the Host. Install the interrupt handler and setup the interrupt mapping */ _UCCINT_registerExternalHandler(11, (_UCCINT_EXTINT_HANDLER_T *)&hal_irq_handler, (void *)hostport_ctx3, false); /* Swap the register directions within the port structure */ unsigned long tmp = hostport_ctx3->cmdReg_toHost; hostport_ctx3->cmdReg_toHost = hostport_ctx3->cmdReg_toRPU; hostport_ctx3->cmdReg_toRPU = tmp; hostport_ctx3->ackReg_toHost -= 4; /* Enable the interrupt */ UCC_HW_WRITE32(ABS_SYS_UCCP_CORE_MTX_INT_ENABLE, SYS_UCCP_CORE_MTX_INT_EN_MASK); } void img_sys_set_mac_address(unsigned char *user_mac_addr) { conv_byte_to_str(umac_mac_addr, user_mac_addr, ETH_ALEN); mac_addr = umac_mac_addr; return; } unsigned char *img_sys_get_mac_address(void) { return vif_macs[0]; } int hal_start(void) { hpriv->hal_disabled = 0; return 0; } int hal_deinit(void *dev) { struct lst_node *cmd_buff_node; (void)(dev); _rpu_umac_if_exit(); /* Free irq line */ while ((cmd_buff_node = LST_removeHead(&hpriv->txq))) kfree(cmd_buff_node); hpriv = NULL; return 0; } int hal_init(void *dev) { struct proc_dir_entry *main_dir_entry; int err = 0; (void) (dev); /* Register irq handler */ IF_UMAC_COLD_BOOT chg_irq_register(); ENDIF_UMAC_COLD_BOOT LST_init(&hpriv->txq); IF_UMAC_COLD_BOOT if (_rpu_umac_if_init(&main_dir_entry) < 0) { err = -ENOMEM; goto error; } ENDIF_UMAC_COLD_BOOT error: return err; } void hal_deinit_bufs(void) { hpriv->hal_disabled = 1; } struct hal_ops_tag hal_ops = { .init = hal_init, .deinit = hal_deinit, .start = hal_start, .send = hal_send, .deinit_bufs = hal_deinit_bufs, };