Beispiel #1
0
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;
}
Beispiel #2
0
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;
}
Beispiel #3
0
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;
}
Beispiel #4
0
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;
}
Beispiel #5
0
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;
}
Beispiel #6
0
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;
	}
}
Beispiel #7
0
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;
}
Beispiel #8
0
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;
}
Beispiel #9
0
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;
}
Beispiel #10
0
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;
}
Beispiel #11
0
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;
}
Beispiel #12
0
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;
}
Beispiel #13
0
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;
}
Beispiel #14
0
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;
}
Beispiel #15
0
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;
}
Beispiel #16
0
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;
}
Beispiel #17
0
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;
}
Beispiel #18
0
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);
}
Beispiel #19
0
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;
}
Beispiel #20
0
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;
}
Beispiel #21
0
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;
}
Beispiel #22
0
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;
}
Beispiel #23
0
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;
}