int rhea_tcam_get(struct rhea_channel *channel, unsigned tcam_base, unsigned tcam_offset, unsigned *qpn_offset, unsigned *pattern, unsigned *mask) { int rc = 0; struct rhea_pport *pport; if (NULL == channel) return -EINVAL; pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } spin_lock(&pport->lock); rc = _rhea_tcam_register_get(channel, tcam_base, tcam_offset, qpn_offset, pattern, mask); if (rc) { spin_unlock(&pport->lock); rhea_error("Was not able to get TCAM registers"); return rc; } spin_unlock(&pport->lock); return rc; }
int rhea_hasher_free(struct rhea_channel *channel) { int rc = 0; struct rhea_pport *pport; if (NULL == channel) return -EINVAL; /* always get pport from channel */ pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } spin_lock(&pport->lock); rc = _rhea_hasher_free(channel); if (rc) { rhea_error("Was not able to free hasher"); return rc; } spin_unlock(&pport->lock); return rc; }
int hea_eq0_free(struct rhea_eq0 *eq0) { int rc; if (NULL == eq0) { rhea_error("Invalid parameters passed in"); return -EINVAL; } rhea_debug("Clean EQ0"); spin_lock(&eq0->lock); /* tell handler to go away */ eq0->stop = 1; rc = rhea_eq_destroy(eq0->eq); if (rc) rhea_error("Could not free EQ0"); /* wait for work queue to finish */ if (eq0->irq_workqueue) { cancel_delayed_work(&eq0->irq_work); flush_workqueue(eq0->irq_workqueue); /* delete queue */ destroy_workqueue(eq0->irq_workqueue); eq0->irq_workqueue = NULL; } del_timer_sync(&eq0->timer); memset(eq0, 0, sizeof(*eq0)); return rc; }
int rhea_tcam_register_set_status(struct rhea_channel *channel, unsigned tcam_base, unsigned tcam_offset, unsigned enable) { int rc = 0; struct rhea_pport *pport; if (NULL == channel) return -EINVAL; pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } spin_lock(&pport->lock); /* get the real index in the TCAM array */ rc = _rhea_tcam_register_set_status(channel, tcam_base, tcam_offset, enable); if (rc) { spin_unlock(&pport->lock); rhea_error("Was not able to set tcam status"); return rc; } spin_unlock(&pport->lock); return rc; }
int rhea_tcam_free(struct rhea_channel *channel, unsigned base) { int rc = 0; struct rhea_pport *pport; if (NULL == channel) return -EINVAL; pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } spin_lock(&pport->lock); /* mark block as free */ rc = _rhea_tcam_free(channel, base); if (rc) { spin_unlock(&pport->lock); rhea_error("Was not able to free resources"); return rc; } spin_unlock(&pport->lock); return rc; }
static void _rhea_hasher_channel_register_set(struct rhea_channel *channel, unsigned hash_bits) { u64 reg = 0x0ULL; struct rhea_pport *pport; struct rhea_pport_bpfc *bpfc; if (NULL == channel) return; /* always get pport from channel */ pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return; } if (NULL == channel->qpn) { rhea_error("Only the main channel ID can set the hasher"); return; } bpfc = &pport->pport_regs->bpfc; /* reset number of used hash bits for all channels */ switch (channel->type) { case HEA_UC_PORT: reg = in_be64(&bpfc->p_rcu); reg = hea_set_u64_bits(reg, hash_bits, 9, 11); out_be64(&bpfc->p_rcu, reg); break; case HEA_MC_PORT: reg = in_be64(&bpfc->p_rcm); reg = hea_set_u64_bits(reg, hash_bits, 9, 11); out_be64(&bpfc->p_rcm, reg); break; case HEA_BC_PORT: reg = in_be64(&bpfc->p_rcb); reg = hea_set_u64_bits(reg, hash_bits, 9, 11); out_be64(&bpfc->p_rcb, reg); break; default: if (0 <= channel->type - HEA_LPORT_0) { int lport_index = hea_lport_index_get(channel->type); reg = in_be64(&bpfc->pl_rc[lport_index]); reg = hea_set_u64_bits(reg, hash_bits, 9, 11); out_be64(&bpfc->pl_rc[lport_index], reg); } break; } }
int rhea_hasher_set(struct rhea_channel *channel, u64 sc, u64 mask0, u64 mask1) { int rc = 0; unsigned hash_bits = 0; struct rhea_pport *pport = NULL; struct rhea_channel_resource_map *map_qpn = NULL; if (NULL == channel) return -EINVAL; /* always get pport from channel */ pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } if (NULL == channel->qpn) { rhea_error("Only the main channel ID can set the hasher"); return -EINVAL; } spin_lock(&pport->lock); /* set registers */ out_be64(&pport->pport_regs->bpfc.pg_hashm[0], mask0); out_be64(&pport->pport_regs->bpfc.pg_hashm[1], mask1); out_be64(&pport->pport_regs->bpfc.pg_hashsc, sc); /* save the values */ pport->hasher->mask0 = mask0; pport->hasher->mask1 = mask1; pport->hasher->sc = sc; map_qpn = _rhea_channel_resource_map_get(channel->qpn, channel->qpn_base); if (NULL == map_qpn) { rhea_error("Was not able to find the QPN map"); return -EINVAL; } /* get number of bits used by qpn alloc */ hash_bits = map_qpn->bits; rhea_debug("Hash bits: %u", hash_bits); /* sets the bits for the hasher */ _rhea_hasher_channel_register_set(channel, hash_bits); spin_unlock(&pport->lock); return rc; }
static int _rhea_tcam_set(struct rhea_channel *channel, unsigned tcam_base, unsigned tcam_offset, unsigned qpn_offset, unsigned pattern, unsigned mask) { int rc = 0; unsigned tcam_bits; struct rhea_pport *pport; struct rhea_channel_resource_map *map_qpn = NULL; if (NULL == channel) return -EINVAL; pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } if (NULL == channel->qpn) { rhea_error("QPN not not allocated!"); return -EINVAL; } if (NULL == channel->tcam) { rhea_error("TCAM not not allocated!"); return -EINVAL; } rhea_debug("Set TCAM slot: %u and channel: %u of pport: " "%u for QPN slot: %u", tcam_base + tcam_offset, channel->type, channel->pport_nr + 1, channel->qpn_base + qpn_offset); map_qpn = _rhea_channel_resource_map_get(channel->qpn, channel->qpn_base); if (NULL == map_qpn) { rhea_error("Was not able to find the QPN map"); return -EINVAL; } rc = _rhea_tcam_register_set(channel, tcam_base, tcam_offset, qpn_offset, pattern, mask); if (rc) { rhea_error("Was not able to set TCAM registers"); return rc; } /* get number of bits used by qpn alloc */ tcam_bits = map_qpn->bits; _rhea_tcam_channel_register_set(channel, tcam_bits); return rc; }
struct rhea_hasher *rhea_hasher_alloc(struct rhea_channel *channel) { struct rhea_pport *pport; struct rhea_hasher *hasher; if (NULL == channel) return NULL; if (!is_hea_lport(channel->type) && HEA_DEFAULT_CHANNEL_SHARE == channel->channel_cfg.dc.channel_usuage) { rhea_warning("Shared channel is not allowed to hasher"); return NULL; } /* always get pport from channel */ pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return NULL; } spin_lock(&pport->lock); if (pport->hasher) { spin_unlock(&pport->lock); rhea_error("Hasher is already allocated"); return NULL; } pport->hasher = rhea_align_alloc(sizeof(*pport->hasher), 8, GFP_KERNEL); if (NULL == pport->hasher) { spin_unlock(&pport->lock); rhea_error("Was not able to allocate hasher"); return NULL; } /* there can only be one --> identifies channel which is using it! */ pport->hasher->id = channel->id; /* pass id back to caller */ hasher = pport->hasher; /* mark that this channel is using the hasher */ channel->hasher_used = 1; rhea_info("Allocated HASHER for channel: %u of pport: %u", channel->type, channel->pport_nr + 1); spin_unlock(&pport->lock); return hasher; }
static inline int _eq0_irq_port_event(struct rhea_eq0 *eq0, unsigned int pport_nr) { int rc; int i; int link_state; rhea_debug("pport state change: %u", pport_nr + 1); /* handle with the state change in the system */ link_state = rhea_pport_link_state_get(pport_nr); if (0 > link_state) { rhea_error("Was not able to change the state of the channel"); rc = link_state; goto out; } rc = rhea_pport_err_reset(pport_nr); if (rc) rhea_error("Could not reset uaelog for pport: %u", pport_nr + 1); rhea_debug("Found state change in pport[%u] to %u", pport_nr + 1, link_state); /* let the rest know what happened */ for (i = 0; i < HEA_MAX_PPORT_CHANNEL_COUNT; ++i) { hea_pport_link_state_callback_t callback = eq0->pport_state_change[pport_nr][i].fkt_ptr; /* check for registered call-backs */ if (callback) { void *args; args = eq0->pport_state_change[pport_nr][i].args; /* execute callback */ rc = (*callback)(pport_nr, link_state, args); if (rc) { rhea_error("Error when dealing with " "link state change"); goto out; } } } return 0; out: return rc; }
int _rhea_hasher_fini(struct rhea_pport *pport) { int i; int rc = 0; if (NULL == pport) return -EINVAL; if (pport->hasher) { rc = _rhea_hasher_free(pport->channel[pport->hasher->id]); if (rc) rhea_error("Was not able to free hasher!"); } /* make sure that the registers are set to their default values */ _rhea_hasher_register_reset(&pport->pport_regs->bpfc); for (i = 0; i < HEA_MAX_PPORT_CHANNEL_COUNT; ++i) { /* if used reset hash bits */ if (pport->channel) _rhea_hasher_channel_register_set(pport->channel[i], 0); } return rc; }
int _rhea_hasher_free(struct rhea_channel *channel) { int rc = 0; struct rhea_pport *pport; if (NULL == channel) return -EINVAL; /* always get pport from channel */ pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } if (channel->hasher_used && pport->hasher) { rhea_align_free(pport->hasher, sizeof(*pport->hasher)); /* set registers to their default values */ _rhea_hasher_register_reset(&pport->pport_regs->bpfc); _rhea_hasher_channel_register_set(channel, 0); channel->hasher_used = 0; pport->hasher = NULL; } return rc; }
int _rhea_tcam_init(struct rhea_pport *pport) { int i; int rc = 0; if (NULL == pport) return -EINVAL; /* initialise resource */ rc = _rhea_channel_resource_init(&pport->tcam, ARRAY_SIZE(pport->pport_regs->bpfc. pg_tcampr), 0, 0, 1); if (rc) { rhea_error("Was not able to initialise TCAM resource: %i", rc); return rc; } for (i = 0; i < HEA_MAX_PPORT_CHANNEL_COUNT; ++i) { /* if used reset hash bits */ if (pport->channel) _rhea_tcam_channel_register_set(pport->channel[i], 0); } /* make sure that the registers are set to their default values */ _rhea_tcam_register_reset(&pport->pport_regs->bpfc); return rc; }
int rhea_hasher_get(struct rhea_channel *channel, u64 *sc, u64 *mask0, u64 *mask1) { int rc = 0; struct rhea_pport *pport; if (NULL == channel) return -EINVAL; if (NULL == sc || NULL == mask0 || NULL == mask1) return -EINVAL; /* always get pport from channel */ pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } spin_lock(&pport->lock); /* get register values */ *mask0 = in_be64(&pport->pport_regs->bpfc.pg_hashm[0]); *mask1 = in_be64(&pport->pport_regs->bpfc.pg_hashm[1]); *sc = in_be64(&pport->pport_regs->bpfc.pg_hashsc); spin_unlock(&pport->lock); return rc; }
int _rhea_tcam_free_all(struct rhea_channel *channel) { int rc = 0; struct rhea_pport *pport; /* get map with new base */ struct rhea_channel_resource_map *map_tcam = NULL; if (NULL == channel) return -EINVAL; if (NULL == channel->tcam) { rhea_error("TCAM not allocated"); return -EINVAL; } pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } /* get first element */ map_tcam = _rhea_channel_resource_map_element_first(channel->tcam); while (NULL != map_tcam) { unsigned base = map_tcam->base; /* free all tcam resources of this instance */ rc = _rhea_tcam_free(channel, base); if (rc) { rhea_error("Was not able to free tcam"); return rc; } /* get next element */ map_tcam = _rhea_channel_resource_map_element_next(channel->tcam, base); } rc = _rhea_channel_map_fini(&pport->tcam, &channel->tcam); if (rc) rhea_error("Was not able to free TCAM"); return rc; }
static int _rhea_tcam_register_get(struct rhea_channel *channel, unsigned tcam_base, unsigned tcam_offset, unsigned *qpn_offset, unsigned *pattern, unsigned *mask) { int rc = 0; unsigned tcam_index; u64 reg_pattern; u64 reg_mask; struct rhea_pport *pport; if (NULL == channel || NULL == qpn_offset || NULL == pattern || NULL == mask) return -EINVAL; pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } /* get the real index in the TCAM array */ rc = _rhea_channel_resource_index_get(channel->tcam, tcam_base, tcam_offset, &tcam_index); if (rc) { rhea_error("Was not able to find index in TCAM map"); return -EINVAL; } reg_pattern = in_be64(&pport->pport_regs->bpfc.pg_tcampr[tcam_index]); reg_mask = in_be64(&pport->pport_regs->bpfc.pg_tcamm[tcam_index]); /* get QPN setting */ *qpn_offset = hea_get_u64_bits(reg_pattern, 59, 63); /* get TCAM pattern */ *pattern = hea_get_u64_bits(reg_pattern, 0, 31); /* get TCAM mask */ *mask = hea_get_u64_bits(reg_mask, 0, 31); return rc; }
static int _rhea_tcam_register_set_status(struct rhea_channel *channel, unsigned tcam_base, unsigned tcam_offset, unsigned enable) { int rc = 0; unsigned tcam_index; struct rhea_pport *pport; u64 reg_pattern; if (NULL == channel) return -EINVAL; pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } if (NULL == channel->qpn || NULL == channel->tcam) { rhea_error("TCAM or QPN are not initialised"); return -EINVAL; } /* get the real index in the TCAM array */ rc = _rhea_channel_resource_index_get(channel->tcam, tcam_base, tcam_offset, &tcam_index); if (rc) { rhea_error("Was not able to find index in TCAM map"); return -EINVAL; } reg_pattern = in_be64(&pport->pport_regs->bpfc.pg_tcampr[tcam_index]); /* enable/disable TCAM slot */ reg_pattern = hea_set_u64_bits(reg_pattern, enable ? 1 : 0, 47, 47); out_be64(&pport->pport_regs->bpfc.pg_tcampr[tcam_index], reg_pattern); return rc; }
static void hea_eq0_timer_pport_event(struct work_struct *work) { int pport_nr; int link_state; struct rhea_eq0 *eq0; if (NULL == work) return; eq0 = container_of(work, struct rhea_eq0, timer_work); if (NULL == eq0) return; while (!spin_trylock(&eq0->lock)) { if (0 != __sync_add_and_fetch(&eq0->stop, 0)) return; } if (0 != __sync_add_and_fetch(&eq0->stop, 0)) { spin_unlock(&eq0->lock); return; } for (pport_nr = 0; pport_nr < 2; ++pport_nr) { /* get link state */ link_state = rhea_pport_link_state_get(pport_nr); if (0 > link_state) { rhea_error("Was not able to get the state " "of the pport: %u", pport_nr + 1); goto out; } /* check for a new state, if one has been found --> act */ if (link_state != eq0->link_state[pport_nr]) { rhea_debug("Found different link state"); /* get new state */ eq0->link_state[pport_nr] = link_state; /* handle port event */ _eq0_irq_port_event(eq0, pport_nr); } /* schedule next timer */ if (likely(0 == eq0->stop)) { mod_timer(&eq0->timer, jiffies + msecs_to_jiffies(CONFIG_POWEREN_RHEA_TIMER_MS)); } } out: spin_unlock(&eq0->lock); }
int _rhea_tcam_free(struct rhea_channel *channel, unsigned base) { int rc = 0; unsigned tcam_offset; struct rhea_pport *pport; struct rhea_channel_resource_map *tcam_base; if (NULL == channel) return -EINVAL; pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } if (NULL == channel->tcam) { rhea_error("TCAM was not allocated"); return -EINVAL; } if (NULL == channel->qpn) { rhea_error("QPN was not allocated"); return -EINVAL; } tcam_base = _rhea_channel_resource_map_get(channel->tcam, base); if (NULL == tcam_base) { rhea_error("Did not find this tcam base"); return -EINVAL; } rhea_info("Free %u TCAM slots from base: %u and channel: " "%u of pport: %u", tcam_base->alloced, base, channel->type, channel->pport_nr + 1); /* make sure that the tcam is reset */ for (tcam_offset = 0; tcam_offset < tcam_base->alloced; ++tcam_offset) { unsigned int qpn_offset = 0; unsigned int pattern = 0; unsigned int mask = 0; /* get current tcam configuration */ rc = _rhea_tcam_register_get(channel, base, tcam_offset, &qpn_offset, &pattern, &mask); if (rc) { rhea_error("Was not able to obtain tcam information"); return rc; } /* reset the registers */ rc = _rhea_tcam_set(channel, base, tcam_offset, qpn_offset, 0, 0); if (rc) { rhea_error("Was not able to reset tcam!"); return rc; } /* disable this tcam */ rc = _rhea_tcam_register_set_status(channel, base, tcam_offset, 0); if (rc) { rhea_error("Was not able to disable tcam"); return rc; } } /* mark block as free */ rc = _rhea_channel_resource_free(&pport->tcam, channel->tcam, base); if (rc) { rhea_error("Was not able to free resources"); return rc; } return rc; }
int rhea_tcam_alloc(struct rhea_channel *channel, struct hea_tcam_cfg *tcam_cfg, unsigned *slot_base) { int rc = 0; unsigned slot_decr; struct rhea_pport *pport; if (NULL == channel || NULL == slot_base || NULL == tcam_cfg) return -EINVAL; if (NULL == channel->qpn) { rhea_error("QPN has not been initialised"); return -EINVAL; } if (NULL == channel->tcam) { /* make sure it can be used by somebody */ rc = _rhea_channel_map_init(&channel->tcam); if (rc) { rhea_error("Was not able to free TCAM map"); return rc; } } if (channel->qpn->alloced < tcam_cfg->slot_count) { rhea_error("Number of requested TCAM slots exceeds " "allocated QPN slots!"); return -EINVAL; } slot_decr = tcam_cfg->slot_count; if (!is_hea_lport(channel->type) && HEA_DEFAULT_CHANNEL_SHARE == channel->channel_cfg.dc.channel_usuage) { rhea_info("Shared channel is not allowed to allocate " "TCAM slots"); return -EINVAL; } /* always get pport from channel */ pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } if (pport->hasher) { rhea_error("Hasher is enabled for this port"); return -EINVAL; } if (ARRAY_SIZE(pport->pport_regs->bpfc.pg_tcampr) < tcam_cfg->slot_count) { rhea_error("Number of requested slots is too high!"); return -EINVAL; } spin_lock(&pport->lock); if (0 == slot_decr) { /* allocate the whole QPN array */ slot_decr = pport->tcam.alloced_max; } rc = _rhea_channel_resource_alloc(&pport->tcam, channel->tcam, slot_decr, slot_base); if (rc) { spin_unlock(&pport->lock); rhea_error("Error when allocating resource for channel"); return rc; } rhea_info("Allocated %u TCAM slots from base: %u and channel: " "%u of pport: %u", channel->tcam->alloced, *slot_base, channel->type, channel->pport_nr + 1); spin_unlock(&pport->lock); return rc; }
int hea_eq0_alloc(struct rhea_eq0 *eq0, struct hea_adapter *ap) { int rc; struct hea_eq_context context_eq; struct hea_process process = { 0 }; if (NULL == eq0) { rhea_error("Invalid parameters passed in"); return -EINVAL; } rhea_debug("Create EQ0 for hypervisor"); context_eq.cfg.eqe_count = 16; context_eq.cfg.coalesing2_delay = HEA_EQ_COALESING_DELAY_0; context_eq.cfg.generate_completion_events = HEA_EQ_GEN_COM_EVENT_DISABLE; context_eq.cfg.irq_type = HEA_IRQ_COALESING_2; /* make sure we create a real EQ0 */ process.lpar = 0xFF; eq0->eq = rhea_eq_create(&process, &context_eq.cfg); if (NULL == eq0->eq) { rhea_error("Was not able to allocate EQ0"); return -ENOMEM; } /* make sure that this EQ is released again */ if (0 != eq0->eq->id) { rhea_error("Was not able to get EQ0"); rhea_eq_destroy(eq0->eq); return -EPERM; } /* set base information */ eq0->q.q_begin = (unsigned char *) eq0->eq->q.va; eq0->q.qe_size = sizeof(struct hea_eqe); eq0->q.qe_count = eq0->eq->q.size / sizeof(struct hea_eqe); /* initialise rest */ heaq_init(&eq0->q); eq0->irq_workqueue = create_singlethread_workqueue("EQ0"); if (NULL == eq0->irq_workqueue) { rhea_error("Was not able to allocate workqueue"); return -ENOMEM; } /* prepare work queue */ INIT_DELAYED_WORK(&eq0->irq_work, &eq0_scan_eq); PREPARE_DELAYED_WORK(&eq0->irq_work, &eq0_scan_eq); INIT_WORK(&eq0->timer_work, &hea_eq0_timer_pport_event); PREPARE_WORK(&eq0->timer_work, &hea_eq0_timer_pport_event); /* timer */ setup_timer(&eq0->timer, hea_eq0_timer_callback, (ulong) eq0); rc = mod_timer(&eq0->timer, jiffies + msecs_to_jiffies(CONFIG_POWEREN_RHEA_TIMER_MS)); if (rc) { rhea_error("Error in mod_timer"); goto out; } rc = rhea_interrupts_setup(eq0->eq, ap->name, ap->hwirq_base, ap->hwirq_count, eq0_irq_handler, eq0); if (rc) { rhea_error("Was not able to register interupt " "handler for EQ0"); goto out; } spin_lock_init(&eq0->lock); return 0; out: if (eq0->eq) rhea_eq_destroy(eq0->eq); if (eq0->irq_workqueue) destroy_workqueue(eq0->irq_workqueue); del_timer(&eq0->timer); return rc; }
static int _rhea_tcam_register_set(struct rhea_channel *channel, unsigned tcam_base, unsigned tcam_offset, unsigned qpn_offset, unsigned pattern, unsigned mask) { int rc = 0; unsigned tcam_index; unsigned qpn_index; u64 reg_pattern; u64 reg_mask; struct rhea_pport *pport; if (NULL == channel) return -EINVAL; if (NULL == channel->tcam || NULL == channel->qpn) { rhea_error("TCAM or QPN is not allocated"); return -EINVAL; } pport = _rhea_pport_get(channel->pport_nr); if (NULL == pport) { rhea_error("Invalid pport number"); return -EINVAL; } /* get the real index in the TCAM array */ rc = _rhea_channel_resource_index_get(channel->tcam, tcam_base, tcam_offset, &tcam_index); if (rc) { rhea_error("Was not able to find index in TCAM map"); return -EINVAL; } /* check if the offset is valid for this channel */ rc = _rhea_channel_resource_index_get(channel->qpn, channel->qpn_base, qpn_offset, &qpn_index); if (rc) { rhea_error("Was not able to find index in QPN map"); return -EINVAL; } reg_pattern = in_be64(&pport->pport_regs->bpfc.pg_tcampr[tcam_index]); reg_mask = in_be64(&pport->pport_regs->bpfc.pg_tcamm[tcam_index]); /* set pattern and mask */ reg_pattern = hea_set_u64_bits(reg_pattern, pattern, 0, 31); reg_mask = hea_set_u64_bits(reg_mask, mask, 0, 31); /* configure LPORT or PPORT */ switch (channel->type) { case HEA_BC_PORT: case HEA_MC_PORT: case HEA_UC_PORT: /* case UC_MC_HEA_BC_PORT: */ /* is physical port */ reg_pattern = hea_set_u64_bits(reg_pattern, 0, 48, 48); reg_mask = hea_set_u64_bits(reg_mask, 1, 48, 48); break; default: /* is logical port */ reg_pattern = hea_set_u64_bits(reg_pattern, 1, 48, 48); reg_mask = hea_set_u64_bits(reg_mask, 1, 48, 48); break; } /* configure which channel type is using this TCAM */ switch (channel->type) { case HEA_BC_PORT: reg_pattern = hea_set_u64_bits(reg_pattern, 1, 54, 55); reg_mask = hea_set_u64_bits(reg_mask, 3, 54, 55); break; case HEA_MC_PORT: reg_pattern = hea_set_u64_bits(reg_pattern, 2, 54, 55); reg_mask = hea_set_u64_bits(reg_mask, 3, 54, 55); break; case HEA_UC_PORT: reg_pattern = hea_set_u64_bits(reg_pattern, 3, 54, 55); reg_mask = hea_set_u64_bits(reg_mask, 3, 54, 55); break; default: { int lport_index = hea_lport_index_get(channel->type); /* only allow one logical port at a time * --> not all combinations are possible */ reg_pattern = hea_set_u64_bits(reg_pattern, lport_index, 54, 55); reg_mask = hea_set_u64_bits(reg_mask, 3, 54, 55); } break; } /* This is the offset from the QPN base to be used * if the packet data matches the pattern */ reg_pattern = hea_set_u64_bits(reg_pattern, qpn_offset, 59, 63); /* write back registers */ out_be64(&pport->pport_regs->bpfc.pg_tcampr[tcam_index], reg_pattern); out_be64(&pport->pport_regs->bpfc.pg_tcamm[tcam_index], reg_mask); return rc; }
static void eq0_scan_eq(struct work_struct *work) { int rc = 0; int error_count = 0; struct rhea_eq0 *eq0; struct hea_eqe *eqe_current; const unsigned int sig_nr = SIGTERM; struct delayed_work *delayed_work; if (NULL == work) return; delayed_work = to_delayed_work(work); eq0 = container_of(delayed_work, struct rhea_eq0, irq_work); if (NULL == eq0) return; while (!spin_trylock(&eq0->lock)) { if (0 != __sync_add_and_fetch(&eq0->stop, 0)) return; } if (0 != __sync_add_and_fetch(&eq0->stop, 0)) { spin_unlock(&eq0->lock); return; } /* get current eqe */ eqe_current = eq0->q.qe_current; if (NULL == eqe_current) return; rhea_debug("event 0x%016llx", eqe_current->eqe); while (hea_eqe_is_valid(eqe_current)) { rhea_debug(" event 0x%016llx", eqe_current->eqe); switch (hea_eqe_event_type(eqe_current)) { case HEA_EQE_ET_PORT_EVENT: { /* get physical port number */ int pport_nr = hea_eqe_pport_number(eqe_current) - 1; /* handle the port event */ rc = _eq0_irq_port_event(eq0, pport_nr); if (rc) { ++error_count; goto MARKER_NEXT_QE; } } break; case HEA_EQE_ET_QP_ERROR: case HEA_EQE_ET_QP_ERROR_EQ0: { struct rhea_qp *qp; unsigned int qp_id; qp_id = hea_eqe_qp_number(eqe_current); qp = _rhea_qp_get(qp_id); if (NULL == qp) continue; if (qp->process.pid) { eq0_signal_send(&qp->process, sig_nr); } else { rhea_error("Found QP error in QP %u " " which could not be " "dealt with.", qp_id); BUG_ON(1); } } break; case HEA_EQE_ET_CQ_ERROR: case HEA_EQE_ET_CQ_ERROR_EQ0: { struct rhea_cq *cq; unsigned int cq_id; cq_id = hea_eqe_cq_number(eqe_current); cq = _rhea_cq_get(cq_id); if (NULL == cq) continue; if (cq->process.pid) eq0_signal_send(&cq->process, sig_nr); else { rhea_error("Found CQ error in CQ %u" " which could not be " "dealt with.", cq_id); BUG_ON(1); } } break; case HEA_EQE_ET_EQ_ERROR: { struct rhea_eq *eq; unsigned int eq_id; eq_id = hea_eqe_eq_number(eqe_current); eq = _rhea_eq_get(eq_id); if (NULL == eq) continue; if (eq->process.pid) { eq0_signal_send(&eq->process, sig_nr); } else { rhea_error("Found EQ error in EQ %u" " which could not be " "dealt with.", eq_id); BUG_ON(1); } } break; case HEA_EQE_ET_QP_WARNING: case HEA_EQE_ET_CP_WARNING: case HEA_EQE_ET_FIRST_ERROR_CAPTURE_INFO: case HEA_EQE_ET_COP_CQ_ACCESS_ERROR: case HEA_EQE_ET_COP_QP_ACCESS_ERROR: case HEA_EQE_ET_COP_TICKET_ACCESS_ERROR: case HEA_EQE_ET_COP_TICKET_ERROR: case HEA_EQE_ET_COP_DATA_ERROR: default: rhea_error("EQ was called and I don't know why: %i", hea_eqe_event_type(eqe_current)); BUG_ON(1); break; } MARKER_NEXT_QE: eqe_current->eqe = 0; heaq_set_next_qe(&eq0->q); eqe_current = eq0->q.qe_current; } spin_unlock(&eq0->lock); return; }