From patchwork Wed Feb 19 14:14:48 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Grant Likely X-Patchwork-Id: 24958 Return-Path: X-Original-To: linaro@patches.linaro.org Delivered-To: linaro@patches.linaro.org Received: from mail-ve0-f198.google.com (mail-ve0-f198.google.com [209.85.128.198]) by ip-10-151-82-157.ec2.internal (Postfix) with ESMTPS id E8B292054E for ; Wed, 19 Feb 2014 14:15:26 +0000 (UTC) Received: by mail-ve0-f198.google.com with SMTP id pa12sf640610veb.9 for ; Wed, 19 Feb 2014 06:15:26 -0800 (PST) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20130820; h=x-gm-message-state:mime-version:delivered-to:from:to:cc:subject :date:message-id:in-reply-to:references:sender:precedence:list-id :x-original-sender:x-original-authentication-results:mailing-list :list-post:list-help:list-archive:list-unsubscribe; bh=HnIZfoX/N4Cx68WhwLYyQqTMm8H2XeVsQ9F64sUhWgs=; b=gww6lYYEUwi1h5zx5AA3MBEKWkYKyzID5ikYjfznXbk5zfkt8Yal7I/vkmsZzCFoxi pAp7zYSz82utS8Itvm1NHeN+YmjzEYAgSheZTGMANfdgIBXALTu05orELYVNGOL/db7V xf17MRZEMQB+JozJdvQrtLsZwaaY/055L90F+9rJ7O75EXle67P7i2+R2s23Y7LTE9xW 63ibDsikgJZdZipWFQG/H/m/qUGNGICHOoT3LgqNqFw+ndWWXhBwifF7NRmV2aBu4nEB DtJjwB0jQCeku5v0QNSdJMktO9mZDOOsJVUHDIcXG+I5+1+2p0Es2nf6x+FKDCKZ3YC+ t2fw== X-Gm-Message-State: ALoCoQmSQht0yxY0AwcnT2+AcHZxwi9k2VXULaqCNLKFpUw3QAWuYH03XP9K+jXRjGuaiviGHmHX X-Received: by 10.236.29.45 with SMTP id h33mr7395026yha.45.1392819326663; Wed, 19 Feb 2014 06:15:26 -0800 (PST) MIME-Version: 1.0 X-BeenThere: patchwork-forward@linaro.org Received: by 10.140.90.80 with SMTP id w74ls129428qgd.95.gmail; Wed, 19 Feb 2014 06:15:26 -0800 (PST) X-Received: by 10.53.5.199 with SMTP id co7mr475583vdd.97.1392819326446; Wed, 19 Feb 2014 06:15:26 -0800 (PST) Received: from mail-ve0-f174.google.com (mail-ve0-f174.google.com [209.85.128.174]) by mx.google.com with ESMTPS id dd4si120412vcb.70.2014.02.19.06.15.26 for (version=TLSv1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 19 Feb 2014 06:15:26 -0800 (PST) Received-SPF: neutral (google.com: 209.85.128.174 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) client-ip=209.85.128.174; Received: by mail-ve0-f174.google.com with SMTP id pa12so426131veb.33 for ; Wed, 19 Feb 2014 06:15:26 -0800 (PST) X-Received: by 10.52.61.168 with SMTP id q8mr8185708vdr.40.1392819326342; Wed, 19 Feb 2014 06:15:26 -0800 (PST) X-Forwarded-To: patchwork-forward@linaro.org X-Forwarded-For: patch@linaro.org patchwork-forward@linaro.org Delivered-To: patch@linaro.org Received: by 10.220.174.196 with SMTP id u4csp300626vcz; Wed, 19 Feb 2014 06:15:25 -0800 (PST) X-Received: by 10.68.108.1 with SMTP id hg1mr2488621pbb.80.1392819324777; Wed, 19 Feb 2014 06:15:24 -0800 (PST) Received: from vger.kernel.org (vger.kernel.org. [209.132.180.67]) by mx.google.com with ESMTP id l8si319768pao.326.2014.02.19.06.15.24; Wed, 19 Feb 2014 06:15:24 -0800 (PST) Received-SPF: pass (google.com: best guess record for domain of linux-kernel-owner@vger.kernel.org designates 209.132.180.67 as permitted sender) client-ip=209.132.180.67; Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753973AbaBSOPN (ORCPT + 27 others); Wed, 19 Feb 2014 09:15:13 -0500 Received: from mail-wi0-f176.google.com ([209.85.212.176]:56255 "EHLO mail-wi0-f176.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1753929AbaBSOPF (ORCPT ); Wed, 19 Feb 2014 09:15:05 -0500 Received: by mail-wi0-f176.google.com with SMTP id hi5so4724815wib.3 for ; Wed, 19 Feb 2014 06:15:03 -0800 (PST) X-Received: by 10.194.22.232 with SMTP id h8mr3194282wjf.53.1392819302340; Wed, 19 Feb 2014 06:15:02 -0800 (PST) Received: from trevor.secretlab.ca (host109-153-23-84.range109-153.btcentralplus.com. [109.153.23.84]) by mx.google.com with ESMTPSA id d6sm2090956wiz.4.2014.02.19.06.15.00 for (version=TLSv1.1 cipher=ECDHE-RSA-RC4-SHA bits=128/128); Wed, 19 Feb 2014 06:15:01 -0800 (PST) Received: by trevor.secretlab.ca (Postfix, from userid 1000) id 638EBC4088D; Wed, 19 Feb 2014 14:14:55 +0000 (GMT) From: Grant Likely To: devicetree@vger.kernel.org, linux-kernel@vger.kernel.org Cc: Kevin Hao , Rob Herring , Sebastian Hesselbarth , Grant Likely Subject: [PATCH v4 2/4] of: reimplement the matching method for __of_match_node() Date: Wed, 19 Feb 2014 14:14:48 +0000 Message-Id: <1392819290-1044-3-git-send-email-grant.likely@linaro.org> X-Mailer: git-send-email 1.8.3.2 In-Reply-To: <1392819290-1044-1-git-send-email-grant.likely@linaro.org> References: <1392819290-1044-1-git-send-email-grant.likely@linaro.org> Sender: linux-kernel-owner@vger.kernel.org Precedence: list List-ID: X-Mailing-List: linux-kernel@vger.kernel.org X-Removed-Original-Auth: Dkim didn't pass. X-Original-Sender: grant.likely@linaro.org X-Original-Authentication-Results: mx.google.com; spf=neutral (google.com: 209.85.128.174 is neither permitted nor denied by best guess record for domain of patch+caf_=patchwork-forward=linaro.org@linaro.org) smtp.mail=patch+caf_=patchwork-forward=linaro.org@linaro.org Mailing-list: list patchwork-forward@linaro.org; contact patchwork-forward+owners@linaro.org X-Google-Group-Id: 836684582541 List-Post: , List-Help: , List-Archive: List-Unsubscribe: , From: Kevin Hao In the current implementation of __of_match_node(), it will compare each given match entry against all the node's compatible strings with of_device_is_compatible(). To achieve multiple compatible strings per node with ordering from specific to generic, this requires given matches to be ordered from specific to generic. For most of the drivers this is not true and also an alphabetical ordering is more sane there. Therefore, we define a following priority order for the match, and then scan all the entries to find the best match. 1. specific compatible && type && name 2. specific compatible && type 3. specific compatible && name 4. specific compatible 5. general compatible && type && name 6. general compatible && type 7. general compatible && name 8. general compatible 9. type && name 10. type 11. name v4: Short-circuit failure cases instead of mucking with score, and remove extra __of_device_is_compatible() wrapper stub. Move scoring logic directly into __of_device_is_compatible() v3: Also need to bail out when there does have a compatible member in match entry, but it doesn't match with the device node's compatible. v2: Fix the bug such as we get the same score for the following two match entries with the empty node 'name2 { };' struct of_device_id matches[] = { {.name = "name2", }, {.name = "name2", .type = "type1", }, {} }; Signed-off-by: Kevin Hao [grant.likely: added v4 changes] Signed-off-by: Grant Likely --- drivers/of/base.c | 108 +++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 74 insertions(+), 34 deletions(-) diff --git a/drivers/of/base.c b/drivers/of/base.c index ba195fbce4c6..30ffc291d0a0 100644 --- a/drivers/of/base.c +++ b/drivers/of/base.c @@ -342,27 +342,73 @@ struct device_node *of_get_cpu_node(int cpu, unsigned int *thread) } EXPORT_SYMBOL(of_get_cpu_node); -/** Checks if the given "compat" string matches one of the strings in - * the device's "compatible" property +/** + * __of_device_is_compatible() - Check if the node matches given constraints + * @device: pointer to node + * @compat: required compatible string, NULL or "" for any match + * @type: required device_type value, NULL or "" for any match + * @name: required node name, NULL or "" for any match + * + * Checks if the given @compat, @type and @name strings match the + * properties of the given @device. A constraints can be skipped by + * passing NULL or an empty string as the constraint. + * + * Returns 0 for no match, and a positive integer on match. The return + * value is a relative score with larger values indicating better + * matches. The score is weighted for the most specific compatible value + * to get the highest score. Matching type is next, followed by matching + * name. Practically speaking, this results in the following priority + * order for matches: + * + * 1. specific compatible && type && name + * 2. specific compatible && type + * 3. specific compatible && name + * 4. specific compatible + * 5. general compatible && type && name + * 6. general compatible && type + * 7. general compatible && name + * 8. general compatible + * 9. type && name + * 10. type + * 11. name */ static int __of_device_is_compatible(const struct device_node *device, - const char *compat) + const char *compat, const char *type, const char *name) { const char* cp; - int cplen, l; + int cplen, l, index, score = 0; - cp = __of_get_property(device, "compatible", &cplen); - if (cp == NULL) - return 0; - while (cplen > 0) { - if (of_compat_cmp(cp, compat, strlen(compat)) == 0) - return 1; - l = strlen(cp) + 1; - cp += l; - cplen -= l; + /* Compatible match has highest priority */ + if (compat && compat[0]) { + cp = __of_get_property(device, "compatible", &cplen); + if (!cp) + return 0; + for (index = 0; cplen > 0; index++, cp += l, cplen -= l) { + l = strlen(cp) + 1; + if (of_compat_cmp(cp, compat, strlen(compat)) == 0) { + score = INT_MAX/2 - (index << 2); + break; + } + } + if (!score) + return 0; } - return 0; + /* Matching type is better than matching name */ + if (type && type[0]) { + if (!device->type || of_node_cmp(type, device->type)) + return 0; + score += 2; + } + + /* Matching name is a bit better than not */ + if (name && name[0]) { + if (!device->name || of_node_cmp(name, device->name)) + return 0; + score++; + } + + return score; } /** Checks if the given "compat" string matches one of the strings in @@ -375,7 +421,7 @@ int of_device_is_compatible(const struct device_node *device, int res; raw_spin_lock_irqsave(&devtree_lock, flags); - res = __of_device_is_compatible(device, compat); + res = __of_device_is_compatible(device, compat, NULL, NULL); raw_spin_unlock_irqrestore(&devtree_lock, flags); return res; } @@ -681,10 +727,7 @@ struct device_node *of_find_compatible_node(struct device_node *from, raw_spin_lock_irqsave(&devtree_lock, flags); np = from ? from->allnext : of_allnodes; for (; np; np = np->allnext) { - if (type - && !(np->type && (of_node_cmp(np->type, type) == 0))) - continue; - if (__of_device_is_compatible(np, compatible) && + if (__of_device_is_compatible(np, compatible, type, NULL) && of_node_get(np)) break; } @@ -734,25 +777,22 @@ static const struct of_device_id *__of_match_node(const struct of_device_id *matches, const struct device_node *node) { + const struct of_device_id *best_match = NULL; + int score, best_score = 0; + if (!matches) return NULL; - while (matches->name[0] || matches->type[0] || matches->compatible[0]) { - int match = 1; - if (matches->name[0]) - match &= node->name - && !strcmp(matches->name, node->name); - if (matches->type[0]) - match &= node->type - && !strcmp(matches->type, node->type); - if (matches->compatible[0]) - match &= __of_device_is_compatible(node, - matches->compatible); - if (match) - return matches; - matches++; + for (; matches->name[0] || matches->type[0] || matches->compatible[0]; matches++) { + score = __of_device_is_compatible(node, matches->compatible, + matches->type, matches->name); + if (score > best_score) { + best_match = matches; + best_score = score; + } } - return NULL; + + return best_match; } /**