summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorHaiying Wang <Haiying.Wang@freescale.com>2013-03-11 20:43:14 (GMT)
committerFleming Andrew-AFLEMING <AFLEMING@freescale.com>2013-04-16 16:17:04 (GMT)
commita513177be99be3d96b8eade6f26f3f0f589afb75 (patch)
tree05ccd4e63e64c1814de7307a87135cf910bd4412
parentcf620d252d9e85e6012dcd35ce7a38f73d903661 (diff)
downloadlinux-fsl-qoriq-a513177be99be3d96b8eade6f26f3f0f589afb75.tar.xz
fsl_qman: use a single CGR list per-portal, not 256
CGR objects registered against a portal can receive CSCN notifications via that portal, and this supports the existence of there being more than one CGR object for the same CGRID (eg. two distinct drivers using the same portal and using FQs that are subscribed to the same CGR). The portal code was previously using a distinct list of registered CGRs for every possible CGRID, ie. a 256-element array of lists! This meant that when CSCN interrupts occurred and a 256-bit mask was calculated indicating which CGRIDs had changed state, we would iterate that bitmask and for each CGRID that had changed, we would iterate the corresponding list from the array, invoking callbacks for all CGR objects. Now, we just use a singe list for all CGRs, irrespective of CGRID. Rather than iterating the bitmask by CGRID and, for each CGRID that had a state-change, iterating the corresponding CGR list to invoke callbacks, we now just iterate the single CGR list and for each CGR with a callback, we check the bit in the bitmask corresponding to the CGRID to determine whether to invoke the callback. This is a more efficient use of memory (the 256-element array of lists used 2KB per portal on 32-bit cores, 4KB on 64-bit), and the code becomes simpler. And the "downside" doesn't occur, because there are never more than a small handful of CGR objects per portal at most, and quite often only one or two (or even none). So a single list is probably as efficient or even better in the conventional use cases, and much less wasteful of space. Furthermore, this logic will be extended for CEETM CCGRs, of which there are many more than for regular CGRs. So without this change, the extensions for CEETM would continue the previous bad approach, but with 2 or 4 times the unwelcome footprint. Signed-off-by: Geoff Thorpe <Geoff.Thorpe@freescale.com> Change-Id: I00ff60edf191aabc9105c0b49e7437fad085f7dc Reviewed-on: http://git.am.freescale.net:8181/1258 Reviewed-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com> Tested-by: Fleming Andrew-AFLEMING <AFLEMING@freescale.com>
-rw-r--r--drivers/staging/fsl_qbman/qman_high.c38
-rw-r--r--drivers/staging/fsl_qbman/qman_private.h4
2 files changed, 19 insertions, 23 deletions
diff --git a/drivers/staging/fsl_qbman/qman_high.c b/drivers/staging/fsl_qbman/qman_high.c
index 04290a2..50d0008 100644
--- a/drivers/staging/fsl_qbman/qman_high.c
+++ b/drivers/staging/fsl_qbman/qman_high.c
@@ -99,8 +99,8 @@ struct qman_portal {
char irqname[MAX_IRQNAME];
/* 2-element array. cgrs[0] is mask, cgrs[1] is snapshot. */
struct qman_cgrs *cgrs;
- /* 256-element array, each is a linked-list of CSCN handlers. */
- struct list_head cgr_cbs[256];
+ /* linked-list of CSCN handlers. */
+ struct list_head cgr_cbs;
/* list lock */
spinlock_t cgr_lock;
};
@@ -390,8 +390,7 @@ struct qman_portal *qman_create_affine_portal(
else
/* if the given mask is NULL, assume all CGRs can be seen */
qman_cgrs_fill(&portal->cgrs[0]);
- for (ret = 0; ret < __CGR_NUM; ret++)
- INIT_LIST_HEAD(&portal->cgr_cbs[ret]);
+ INIT_LIST_HEAD(&portal->cgr_cbs);
spin_lock_init(&portal->cgr_lock);
portal->bits = 0;
portal->slowpoll = 0;
@@ -605,7 +604,6 @@ static u32 __poll_portal_slow(struct qman_portal *p, u32 is)
struct qman_cgrs rr, c;
struct qm_mc_result *mcr;
struct qman_cgr *cgr;
- int i;
unsigned long irqflags __maybe_unused;
spin_lock_irqsave(&p->cgr_lock, irqflags);
@@ -627,11 +625,9 @@ static u32 __poll_portal_slow(struct qman_portal *p, u32 is)
/* update snapshot */
qman_cgrs_cp(&p->cgrs[1], &rr);
/* Invoke callback */
- qman_cgrs_for_each_1(i, &c)
- list_for_each_entry(cgr, &p->cgr_cbs[i], node) {
- if (cgr->cb)
- cgr->cb(p, cgr, qman_cgrs_get(&rr, i));
- }
+ list_for_each_entry(cgr, &p->cgr_cbs, node)
+ if (cgr->cb && qman_cgrs_get(&c, cgr->cgrid))
+ cgr->cb(p, cgr, qman_cgrs_get(&rr, cgr->cgrid));
spin_unlock_irqrestore(&p->cgr_lock, irqflags);
}
@@ -2063,9 +2059,8 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags,
cgr->chan = p->config->public_cfg.channel;
spin_lock_irqsave(&p->cgr_lock, irqflags);
- /* if no opts specified and I'm not the first for this portal, just add
- * to the list */
- if ((opts == NULL) && !list_empty(&p->cgr_cbs[cgr->cgrid]))
+ /* if no opts specified, just add it to the list */
+ if (!opts)
goto add_list;
ret = qman_query_cgr(cgr, &cgr_state);
@@ -2090,7 +2085,7 @@ int qman_create_cgr(struct qman_cgr *cgr, u32 flags,
if (ret)
goto release_lock;
add_list:
- list_add(&cgr->node, &p->cgr_cbs[cgr->cgrid]);
+ list_add(&cgr->node, &p->cgr_cbs);
/* Determine if newly added object requires its callback to be called */
ret = qman_query_cgr(cgr, &cgr_state);
@@ -2156,6 +2151,7 @@ int qman_delete_cgr(struct qman_cgr *cgr)
struct qm_mcr_querycgr cgr_state;
struct qm_mcc_initcgr local_opts;
int ret = 0;
+ struct qman_cgr *i;
struct qman_portal *p = get_affine_portal();
if (cgr->chan != p->config->public_cfg.channel) {
@@ -2168,13 +2164,17 @@ int qman_delete_cgr(struct qman_cgr *cgr)
memset(&local_opts, 0, sizeof(struct qm_mcc_initcgr));
spin_lock_irqsave(&p->cgr_lock, irqflags);
list_del(&cgr->node);
- /* If last in list, CSCN_TARG must be set accordingly */
- if (!list_empty(&p->cgr_cbs[cgr->cgrid]))
- goto release_lock;
+ /*
+ * If there are no other CGR objects for this CGRID in the list, update
+ * CSCN_TARG accordingly
+ */
+ list_for_each_entry(i, &p->cgr_cbs, node)
+ if ((i->cgrid == cgr->cgrid) && i->cb)
+ goto release_lock;
ret = qman_query_cgr(cgr, &cgr_state);
if (ret) {
/* add back to the list */
- list_add(&cgr->node, &p->cgr_cbs[cgr->cgrid]);
+ list_add(&cgr->node, &p->cgr_cbs);
goto release_lock;
}
/* Overwrite TARG */
@@ -2188,7 +2188,7 @@ int qman_delete_cgr(struct qman_cgr *cgr)
ret = qman_modify_cgr(cgr, 0, &local_opts);
if (ret)
/* add back to the list */
- list_add(&cgr->node, &p->cgr_cbs[cgr->cgrid]);
+ list_add(&cgr->node, &p->cgr_cbs);
release_lock:
spin_unlock_irqrestore(&p->cgr_lock, irqflags);
put_portal:
diff --git a/drivers/staging/fsl_qbman/qman_private.h b/drivers/staging/fsl_qbman/qman_private.h
index cea96d6..5945b34 100644
--- a/drivers/staging/fsl_qbman/qman_private.h
+++ b/drivers/staging/fsl_qbman/qman_private.h
@@ -98,10 +98,6 @@ static inline void qman_cgrs_xor(struct qman_cgrs *dest,
*(_d++) = *(_a++) ^ *(_b++);
}
-#define qman_cgrs_for_each_1(cgr, cgrs) \
- for ((cgr) = -1; (cgr) = qman_cgrs_next((cgrs), (cgr)),\
- (cgr) < __CGR_NUM;)
-
/* used by CCSR and portal interrupt code */
enum qm_isr_reg {
qm_isr_status = 0,