Re: [PATCH 4.9 27/75] net: igmp: Use correct source address on IGMPv3 reports
On Tue, Jan 16, 2018 at 1:18 AM, Sebastian Gottschallwrote: > >> According to my understanding of igmpv3_newpack(), the destination >> address should always be IGMPV3_ALL_MCR = 224.0.0.22. That is what I >> see in my testing. >> >> However, your packet trace says 239.35.100.8. I don't know how the >> code that we touched would be generating an IGMPv2 packet with that >> destination address. > > easy answer from wikipedia. 224.0.x.x is not the only multicast block AFAICT the code that was changed by this patch should not have anything to do with other multicast blocks. It generates an IGMPv3 report with destination address 224.0.0.22. So it would be useful to get more information on how exactly it is causing a failure, so we can find the root cause. >> Would it be possible to get a stack trace for the case where the >> source address is being cleared to 0.0.0.0 in your configuration? > > you mean something like dumpstack and watching the flood comes over me? I would just add something like this into my local tree for testing: WARN_ON_ONCE(pip->saddr == htonl(INADDR_ANY));
Re: [PATCH 4.9 27/75] net: igmp: Use correct source address on IGMPv3 reports
On Tue, Jan 16, 2018 at 1:18 AM, Sebastian Gottschall wrote: > >> According to my understanding of igmpv3_newpack(), the destination >> address should always be IGMPV3_ALL_MCR = 224.0.0.22. That is what I >> see in my testing. >> >> However, your packet trace says 239.35.100.8. I don't know how the >> code that we touched would be generating an IGMPv2 packet with that >> destination address. > > easy answer from wikipedia. 224.0.x.x is not the only multicast block AFAICT the code that was changed by this patch should not have anything to do with other multicast blocks. It generates an IGMPv3 report with destination address 224.0.0.22. So it would be useful to get more information on how exactly it is causing a failure, so we can find the root cause. >> Would it be possible to get a stack trace for the case where the >> source address is being cleared to 0.0.0.0 in your configuration? > > you mean something like dumpstack and watching the flood comes over me? I would just add something like this into my local tree for testing: WARN_ON_ONCE(pip->saddr == htonl(INADDR_ANY));
Re: [PATCH 4.9 27/75] net: igmp: Use correct source address on IGMPv3 reports
On Mon, Jan 15, 2018 at 8:44 PM, Sebastian Gottschall <s.gottsch...@dd-wrt.com> wrote: > Am 16.01.2018 um 05:32 schrieb Kevin Cernekee: >> >> On Mon, Jan 15, 2018 at 8:26 PM, Sebastian Gottschall >> <s.gottsch...@dd-wrt.com> wrote: >>> >>> havent check the source addresses right now. i basicly discovered that >>> this >>> patch breaks the igmp routing and all traffic stops >>> this here is from a working system with the reverted patch. if you really >>> need that i break it again using the patch you need to wait a little bit >>> >>> 05:14:22.697962 IP 10.88.195.138 > 239.35.100.8: igmp v2 report >>> 239.35.100.8 >> >> The patch should only affect IGMPv3 behavior. I did not intend to >> change IGMPv2 behavior. If it does, that might be a bug. > > it does change the behaviour indeed. i dont know the reason. but i while > discovering the issue on 4.14 last week and newly on 4.9 this week while > testing > (my latest firmware i builded was from 30. december and worked) i got > tracked it down to this small patch and it immediatly worked after reverting > it >> >> Is it possible that the kernel is using a source IP of 0.0.0.0, but >> another host does not recognize it because it does not comply with RFC >> 3376? > > this is possible yes, but i cannot look into the "deutsche telekom" host >> >> >> Before/after packet traces would be the best way to see if the kernel >> change is causing it to violate the standard. > > let me just take a look into our patch > + for_ifa(in_dev) { > + if (inet_ifa_match(fl4->saddr, ifa)) > + return fl4->saddr; > + } endfor_ifa(in_dev); > this looks like you're checking if the source address matches to a local > interface, if not you return 0.0.0.0 instead of the source address > > (193.158.35.251, 239.35.20.4)Iif: ppp0 Oifs: briptv > > our first source address here 193.158.35.251 is from a remote network. so > your patch also will change the behaviour since the source address will get > ignored According to my understanding of igmpv3_newpack(), the destination address should always be IGMPV3_ALL_MCR = 224.0.0.22. That is what I see in my testing. However, your packet trace says 239.35.100.8. I don't know how the code that we touched would be generating an IGMPv2 packet with that destination address. Would it be possible to get a stack trace for the case where the source address is being cleared to 0.0.0.0 in your configuration?
Re: [PATCH 4.9 27/75] net: igmp: Use correct source address on IGMPv3 reports
On Mon, Jan 15, 2018 at 8:44 PM, Sebastian Gottschall wrote: > Am 16.01.2018 um 05:32 schrieb Kevin Cernekee: >> >> On Mon, Jan 15, 2018 at 8:26 PM, Sebastian Gottschall >> wrote: >>> >>> havent check the source addresses right now. i basicly discovered that >>> this >>> patch breaks the igmp routing and all traffic stops >>> this here is from a working system with the reverted patch. if you really >>> need that i break it again using the patch you need to wait a little bit >>> >>> 05:14:22.697962 IP 10.88.195.138 > 239.35.100.8: igmp v2 report >>> 239.35.100.8 >> >> The patch should only affect IGMPv3 behavior. I did not intend to >> change IGMPv2 behavior. If it does, that might be a bug. > > it does change the behaviour indeed. i dont know the reason. but i while > discovering the issue on 4.14 last week and newly on 4.9 this week while > testing > (my latest firmware i builded was from 30. december and worked) i got > tracked it down to this small patch and it immediatly worked after reverting > it >> >> Is it possible that the kernel is using a source IP of 0.0.0.0, but >> another host does not recognize it because it does not comply with RFC >> 3376? > > this is possible yes, but i cannot look into the "deutsche telekom" host >> >> >> Before/after packet traces would be the best way to see if the kernel >> change is causing it to violate the standard. > > let me just take a look into our patch > + for_ifa(in_dev) { > + if (inet_ifa_match(fl4->saddr, ifa)) > + return fl4->saddr; > + } endfor_ifa(in_dev); > this looks like you're checking if the source address matches to a local > interface, if not you return 0.0.0.0 instead of the source address > > (193.158.35.251, 239.35.20.4)Iif: ppp0 Oifs: briptv > > our first source address here 193.158.35.251 is from a remote network. so > your patch also will change the behaviour since the source address will get > ignored According to my understanding of igmpv3_newpack(), the destination address should always be IGMPV3_ALL_MCR = 224.0.0.22. That is what I see in my testing. However, your packet trace says 239.35.100.8. I don't know how the code that we touched would be generating an IGMPv2 packet with that destination address. Would it be possible to get a stack trace for the case where the source address is being cleared to 0.0.0.0 in your configuration?
Re: [PATCH 4.9 27/75] net: igmp: Use correct source address on IGMPv3 reports
On Mon, Jan 15, 2018 at 8:26 PM, Sebastian Gottschallwrote: > havent check the source addresses right now. i basicly discovered that this > patch breaks the igmp routing and all traffic stops > this here is from a working system with the reverted patch. if you really > need that i break it again using the patch you need to wait a little bit > > 05:14:22.697962 IP 10.88.195.138 > 239.35.100.8: igmp v2 report 239.35.100.8 The patch should only affect IGMPv3 behavior. I did not intend to change IGMPv2 behavior. If it does, that might be a bug. Is it possible that the kernel is using a source IP of 0.0.0.0, but another host does not recognize it because it does not comply with RFC 3376? Before/after packet traces would be the best way to see if the kernel change is causing it to violate the standard.
Re: [PATCH 4.9 27/75] net: igmp: Use correct source address on IGMPv3 reports
On Mon, Jan 15, 2018 at 8:26 PM, Sebastian Gottschall wrote: > havent check the source addresses right now. i basicly discovered that this > patch breaks the igmp routing and all traffic stops > this here is from a working system with the reverted patch. if you really > need that i break it again using the patch you need to wait a little bit > > 05:14:22.697962 IP 10.88.195.138 > 239.35.100.8: igmp v2 report 239.35.100.8 The patch should only affect IGMPv3 behavior. I did not intend to change IGMPv2 behavior. If it does, that might be a bug. Is it possible that the kernel is using a source IP of 0.0.0.0, but another host does not recognize it because it does not comply with RFC 3376? Before/after packet traces would be the best way to see if the kernel change is causing it to violate the standard.
Re: [PATCH 4.9 27/75] net: igmp: Use correct source address on IGMPv3 reports
On Mon, Jan 15, 2018 at 7:50 PM, Sebastian Gottschallwrote: > please revert that on 4.9 and 4.14 > it breaks igmp routing. it can be reproduced with any iptv connection using > igmp-proxy. reverting this patch fixes the issue. Hi Sebastian, Is this the correct igmp-proxy (based on mrouted)? https://github.com/mirror/dd-wrt/tree/master/src/router/igmp-proxy What is the actual vs. expected source address you are seeing on the IGMP packets?
Re: [PATCH 4.9 27/75] net: igmp: Use correct source address on IGMPv3 reports
On Mon, Jan 15, 2018 at 7:50 PM, Sebastian Gottschall wrote: > please revert that on 4.9 and 4.14 > it breaks igmp routing. it can be reproduced with any iptv connection using > igmp-proxy. reverting this patch fixes the issue. Hi Sebastian, Is this the correct igmp-proxy (based on mrouted)? https://github.com/mirror/dd-wrt/tree/master/src/router/igmp-proxy What is the actual vs. expected source address you are seeing on the IGMP packets?
[PATCH] net: igmp: Use correct source address on IGMPv3 reports
Closing a multicast socket after the final IPv4 address is deleted from an interface can generate a membership report that uses the source IP from a different interface. The following test script, run from an isolated netns, reproduces the issue: #!/bin/bash ip link add dummy0 type dummy ip link add dummy1 type dummy ip link set dummy0 up ip link set dummy1 up ip addr add 10.1.1.1/24 dev dummy0 ip addr add 192.168.99.99/24 dev dummy1 tcpdump -U -i dummy0 & socat EXEC:"sleep 2" \ UDP4-DATAGRAM:239.101.1.68:8889,ip-add-membership=239.0.1.68:10.1.1.1 & sleep 1 ip addr del 10.1.1.1/24 dev dummy0 sleep 5 kill %tcpdump RFC 3376 specifies that the report must be sent with a valid IP source address from the destination subnet, or from address 0.0.0.0. Add an extra check to make sure this is the case. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- net/ipv4/igmp.c | 20 +++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d1f8f302dbf3..0672264c9d93 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -89,6 +89,7 @@ #include #include #include +#include #include #include @@ -321,6 +322,23 @@ igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted) return scount; } +/* source address selection per RFC 3376 section 4.2.13 */ +static __be32 igmpv3_get_srcaddr(struct net_device *dev, +const struct flowi4 *fl4) +{ + struct in_device *in_dev = __in_dev_get_rcu(dev); + + if (!in_dev) + return htonl(INADDR_ANY); + + for_ifa(in_dev) { + if (inet_ifa_match(fl4->saddr, ifa)) + return fl4->saddr; + } endfor_ifa(in_dev); + + return htonl(INADDR_ANY); +} + static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) { struct sk_buff *skb; @@ -368,7 +386,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) pip->frag_off = htons(IP_DF); pip->ttl = 1; pip->daddr= fl4.daddr; - pip->saddr= fl4.saddr; + pip->saddr= igmpv3_get_srcaddr(dev, ); pip->protocol = IPPROTO_IGMP; pip->tot_len = 0; /* filled in later */ ip_select_ident(net, skb, NULL); -- 2.15.1.424.g9478a66081-goog
[PATCH] net: igmp: Use correct source address on IGMPv3 reports
Closing a multicast socket after the final IPv4 address is deleted from an interface can generate a membership report that uses the source IP from a different interface. The following test script, run from an isolated netns, reproduces the issue: #!/bin/bash ip link add dummy0 type dummy ip link add dummy1 type dummy ip link set dummy0 up ip link set dummy1 up ip addr add 10.1.1.1/24 dev dummy0 ip addr add 192.168.99.99/24 dev dummy1 tcpdump -U -i dummy0 & socat EXEC:"sleep 2" \ UDP4-DATAGRAM:239.101.1.68:8889,ip-add-membership=239.0.1.68:10.1.1.1 & sleep 1 ip addr del 10.1.1.1/24 dev dummy0 sleep 5 kill %tcpdump RFC 3376 specifies that the report must be sent with a valid IP source address from the destination subnet, or from address 0.0.0.0. Add an extra check to make sure this is the case. Signed-off-by: Kevin Cernekee --- net/ipv4/igmp.c | 20 +++- 1 file changed, 19 insertions(+), 1 deletion(-) diff --git a/net/ipv4/igmp.c b/net/ipv4/igmp.c index d1f8f302dbf3..0672264c9d93 100644 --- a/net/ipv4/igmp.c +++ b/net/ipv4/igmp.c @@ -89,6 +89,7 @@ #include #include #include +#include #include #include @@ -321,6 +322,23 @@ igmp_scount(struct ip_mc_list *pmc, int type, int gdeleted, int sdeleted) return scount; } +/* source address selection per RFC 3376 section 4.2.13 */ +static __be32 igmpv3_get_srcaddr(struct net_device *dev, +const struct flowi4 *fl4) +{ + struct in_device *in_dev = __in_dev_get_rcu(dev); + + if (!in_dev) + return htonl(INADDR_ANY); + + for_ifa(in_dev) { + if (inet_ifa_match(fl4->saddr, ifa)) + return fl4->saddr; + } endfor_ifa(in_dev); + + return htonl(INADDR_ANY); +} + static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) { struct sk_buff *skb; @@ -368,7 +386,7 @@ static struct sk_buff *igmpv3_newpack(struct net_device *dev, unsigned int mtu) pip->frag_off = htons(IP_DF); pip->ttl = 1; pip->daddr= fl4.daddr; - pip->saddr= fl4.saddr; + pip->saddr= igmpv3_get_srcaddr(dev, ); pip->protocol = IPPROTO_IGMP; pip->tot_len = 0; /* filled in later */ ip_select_ident(net, skb, NULL); -- 2.15.1.424.g9478a66081-goog
[PATCH V2] netlink: Add netns check on taps
Currently, a nlmon link inside a child namespace can observe systemwide netlink activity. Filter the traffic so that nlmon can only sniff netlink messages from its own netns. Test case: vpnns -- bash -c "ip link add nlmon0 type nlmon; \ ip link set nlmon0 up; \ tcpdump -i nlmon0 -q -w /tmp/nlmon.pcap -U" & sudo ip xfrm state add src 10.1.1.1 dst 10.1.1.2 proto esp \ spi 0x1 mode transport \ auth sha1 0x616263313233 \ enc aes 0x grep --binary abc123 /tmp/nlmon.pcap Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- net/netlink/af_netlink.c | 3 +++ 1 file changed, 3 insertions(+) V1->V2: Drop the special exception for init_net. Compile-tested only, will retest later today. diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b9e0ee4..79cc1bf 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -253,6 +253,9 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb, struct sock *sk = skb->sk; int ret = -ENOMEM; + if (!net_eq(dev_net(dev), sock_net(sk))) + return 0; + dev_hold(dev); if (is_vmalloc_addr(skb->head)) -- 2.7.4
[PATCH V2] netlink: Add netns check on taps
Currently, a nlmon link inside a child namespace can observe systemwide netlink activity. Filter the traffic so that nlmon can only sniff netlink messages from its own netns. Test case: vpnns -- bash -c "ip link add nlmon0 type nlmon; \ ip link set nlmon0 up; \ tcpdump -i nlmon0 -q -w /tmp/nlmon.pcap -U" & sudo ip xfrm state add src 10.1.1.1 dst 10.1.1.2 proto esp \ spi 0x1 mode transport \ auth sha1 0x616263313233 \ enc aes 0x grep --binary abc123 /tmp/nlmon.pcap Signed-off-by: Kevin Cernekee --- net/netlink/af_netlink.c | 3 +++ 1 file changed, 3 insertions(+) V1->V2: Drop the special exception for init_net. Compile-tested only, will retest later today. diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b9e0ee4..79cc1bf 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -253,6 +253,9 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb, struct sock *sk = skb->sk; int ret = -ENOMEM; + if (!net_eq(dev_net(dev), sock_net(sk))) + return 0; + dev_hold(dev); if (is_vmalloc_addr(skb->head)) -- 2.7.4
Re: [PATCH] netlink: Add netns check on taps
On Tue, Dec 5, 2017 at 6:19 PM, David Ahernwrote: >> + if (!net_eq(dev_net(dev), sock_net(sk)) && >> + !net_eq(dev_net(dev), _net)) { > > Why is init_net special? Seems like snooping should be limited to the > namespace you are in. Depends how important it is to preserve the current "typical use case" behavior, where the root user in the init netns can see all netlink traffic on the system.
Re: [PATCH] netlink: Add netns check on taps
On Tue, Dec 5, 2017 at 6:19 PM, David Ahern wrote: >> + if (!net_eq(dev_net(dev), sock_net(sk)) && >> + !net_eq(dev_net(dev), _net)) { > > Why is init_net special? Seems like snooping should be limited to the > namespace you are in. Depends how important it is to preserve the current "typical use case" behavior, where the root user in the init netns can see all netlink traffic on the system.
[PATCH] netfilter: xt_osf: Add missing permission checks
The capability check in nfnetlink_rcv() verifies that the caller has CAP_NET_ADMIN in the namespace that "owns" the netlink socket. However, xt_osf_fingers is shared by all net namespaces on the system. An unprivileged user can create user and net namespaces in which he holds CAP_NET_ADMIN to bypass the netlink_net_capable() check: vpnns -- nfnl_osf -f /tmp/pf.os vpnns -- nfnl_osf -f /tmp/pf.os -d These non-root operations successfully modify the systemwide OS fingerprint list. Add new capable() checks so that they can't. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- net/netfilter/xt_osf.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 36e14b1..a34f314 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,9 @@ static int xt_osf_add_callback(struct net *net, struct sock *ctnl, struct xt_osf_finger *kf = NULL, *sf; int err = 0; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!osf_attrs[OSF_ATTR_FINGER]) return -EINVAL; @@ -115,6 +119,9 @@ static int xt_osf_remove_callback(struct net *net, struct sock *ctnl, struct xt_osf_finger *sf; int err = -ENOENT; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!osf_attrs[OSF_ATTR_FINGER]) return -EINVAL; -- 2.7.4
[PATCH] netfilter: xt_osf: Add missing permission checks
The capability check in nfnetlink_rcv() verifies that the caller has CAP_NET_ADMIN in the namespace that "owns" the netlink socket. However, xt_osf_fingers is shared by all net namespaces on the system. An unprivileged user can create user and net namespaces in which he holds CAP_NET_ADMIN to bypass the netlink_net_capable() check: vpnns -- nfnl_osf -f /tmp/pf.os vpnns -- nfnl_osf -f /tmp/pf.os -d These non-root operations successfully modify the systemwide OS fingerprint list. Add new capable() checks so that they can't. Signed-off-by: Kevin Cernekee --- net/netfilter/xt_osf.c | 7 +++ 1 file changed, 7 insertions(+) diff --git a/net/netfilter/xt_osf.c b/net/netfilter/xt_osf.c index 36e14b1..a34f314 100644 --- a/net/netfilter/xt_osf.c +++ b/net/netfilter/xt_osf.c @@ -19,6 +19,7 @@ #include #include +#include #include #include #include @@ -70,6 +71,9 @@ static int xt_osf_add_callback(struct net *net, struct sock *ctnl, struct xt_osf_finger *kf = NULL, *sf; int err = 0; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!osf_attrs[OSF_ATTR_FINGER]) return -EINVAL; @@ -115,6 +119,9 @@ static int xt_osf_remove_callback(struct net *net, struct sock *ctnl, struct xt_osf_finger *sf; int err = -ENOENT; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!osf_attrs[OSF_ATTR_FINGER]) return -EINVAL; -- 2.7.4
[PATCH] netlink: Add netns check on taps
Currently, a nlmon link inside a child namespace can observe systemwide netlink activity. Filter the traffic so that in a non-init netns, nlmon can only sniff netlink messages from its own netns. Test case: vpnns -- bash -c "ip link add nlmon0 type nlmon; \ ip link set nlmon0 up; \ tcpdump -i nlmon0 -q -w /tmp/nlmon.pcap -U" & sudo ip xfrm state add src 10.1.1.1 dst 10.1.1.2 proto esp \ spi 0x1 mode transport \ auth sha1 0x616263313233 \ enc aes 0x grep abc123 /tmp/nlmon.pcap Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- net/netlink/af_netlink.c | 5 + 1 file changed, 5 insertions(+) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b9e0ee4..88381a2 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -253,6 +253,11 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb, struct sock *sk = skb->sk; int ret = -ENOMEM; + if (!net_eq(dev_net(dev), sock_net(sk)) && + !net_eq(dev_net(dev), _net)) { + return 0; + } + dev_hold(dev); if (is_vmalloc_addr(skb->head)) -- 2.7.4
[PATCH] netlink: Add netns check on taps
Currently, a nlmon link inside a child namespace can observe systemwide netlink activity. Filter the traffic so that in a non-init netns, nlmon can only sniff netlink messages from its own netns. Test case: vpnns -- bash -c "ip link add nlmon0 type nlmon; \ ip link set nlmon0 up; \ tcpdump -i nlmon0 -q -w /tmp/nlmon.pcap -U" & sudo ip xfrm state add src 10.1.1.1 dst 10.1.1.2 proto esp \ spi 0x1 mode transport \ auth sha1 0x616263313233 \ enc aes 0x grep abc123 /tmp/nlmon.pcap Signed-off-by: Kevin Cernekee --- net/netlink/af_netlink.c | 5 + 1 file changed, 5 insertions(+) diff --git a/net/netlink/af_netlink.c b/net/netlink/af_netlink.c index b9e0ee4..88381a2 100644 --- a/net/netlink/af_netlink.c +++ b/net/netlink/af_netlink.c @@ -253,6 +253,11 @@ static int __netlink_deliver_tap_skb(struct sk_buff *skb, struct sock *sk = skb->sk; int ret = -ENOMEM; + if (!net_eq(dev_net(dev), sock_net(sk)) && + !net_eq(dev_net(dev), _net)) { + return 0; + } + dev_hold(dev); if (is_vmalloc_addr(skb->head)) -- 2.7.4
[PATCH] netfilter: nfnetlink_cthelper: Add missing permission checks
The capability check in nfnetlink_rcv() verifies that the caller has CAP_NET_ADMIN in the namespace that "owns" the netlink socket. However, nfnl_cthelper_list is shared by all net namespaces on the system. An unprivileged user can create user and net namespaces in which he holds CAP_NET_ADMIN to bypass the netlink_net_capable() check: $ nfct helper list nfct v1.4.4: netlink error: Operation not permitted $ vpnns -- nfct helper list { .name = ftp, .queuenum = 0, .l3protonum = 2, .l4protonum = 6, .priv_data_len = 24, .status = enabled, }; Add capable() checks in nfnetlink_cthelper, as this is cleaner than trying to generalize the solution. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- net/netfilter/nfnetlink_cthelper.c | 10 ++ 1 file changed, 10 insertions(+) I think xt_osf has the same issue with respect to xt_osf_fingers. Also, it looks like nlmon devices created in an unprivileged netns can see netlink activity from the init namespace. diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c index 41628b393673..d33ce6d5ebce 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -407,6 +408,9 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, struct nfnl_cthelper *nlcth; int ret = 0; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE]) return -EINVAL; @@ -611,6 +615,9 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl, struct nfnl_cthelper *nlcth; bool tuple_set = false; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (nlh->nlmsg_flags & NLM_F_DUMP) { struct netlink_dump_control c = { .dump = nfnl_cthelper_dump_table, @@ -678,6 +685,9 @@ static int nfnl_cthelper_del(struct net *net, struct sock *nfnl, struct nfnl_cthelper *nlcth, *n; int j = 0, ret; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (tb[NFCTH_NAME]) helper_name = nla_data(tb[NFCTH_NAME]); -- 2.7.4
[PATCH] netfilter: nfnetlink_cthelper: Add missing permission checks
The capability check in nfnetlink_rcv() verifies that the caller has CAP_NET_ADMIN in the namespace that "owns" the netlink socket. However, nfnl_cthelper_list is shared by all net namespaces on the system. An unprivileged user can create user and net namespaces in which he holds CAP_NET_ADMIN to bypass the netlink_net_capable() check: $ nfct helper list nfct v1.4.4: netlink error: Operation not permitted $ vpnns -- nfct helper list { .name = ftp, .queuenum = 0, .l3protonum = 2, .l4protonum = 6, .priv_data_len = 24, .status = enabled, }; Add capable() checks in nfnetlink_cthelper, as this is cleaner than trying to generalize the solution. Signed-off-by: Kevin Cernekee --- net/netfilter/nfnetlink_cthelper.c | 10 ++ 1 file changed, 10 insertions(+) I think xt_osf has the same issue with respect to xt_osf_fingers. Also, it looks like nlmon devices created in an unprivileged netns can see netlink activity from the init namespace. diff --git a/net/netfilter/nfnetlink_cthelper.c b/net/netfilter/nfnetlink_cthelper.c index 41628b393673..d33ce6d5ebce 100644 --- a/net/netfilter/nfnetlink_cthelper.c +++ b/net/netfilter/nfnetlink_cthelper.c @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -407,6 +408,9 @@ static int nfnl_cthelper_new(struct net *net, struct sock *nfnl, struct nfnl_cthelper *nlcth; int ret = 0; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (!tb[NFCTH_NAME] || !tb[NFCTH_TUPLE]) return -EINVAL; @@ -611,6 +615,9 @@ static int nfnl_cthelper_get(struct net *net, struct sock *nfnl, struct nfnl_cthelper *nlcth; bool tuple_set = false; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (nlh->nlmsg_flags & NLM_F_DUMP) { struct netlink_dump_control c = { .dump = nfnl_cthelper_dump_table, @@ -678,6 +685,9 @@ static int nfnl_cthelper_del(struct net *net, struct sock *nfnl, struct nfnl_cthelper *nlcth, *n; int j = 0, ret; + if (!capable(CAP_NET_ADMIN)) + return -EPERM; + if (tb[NFCTH_NAME]) helper_name = nla_data(tb[NFCTH_NAME]); -- 2.7.4
[PATCH V2 2/2] netfilter: ctnetlink: Fix regression in CTA_HELP processing
Prior to Linux 4.4, it was usually harmless to send a CTA_HELP attribute containing the name of the current helper. That is no longer the case: as of Linux 4.4, if ctnetlink_change_helper() returns an error from the ct->master check, processing of the request will fail, skipping the NFQA_EXP attribute (if present). This patch changes the behavior to improve compatibility with user programs that expect the kernel interface to work the way it did prior to Linux 4.4. If a user program specifies CTA_HELP but the argument matches the current conntrack helper name, ignore it instead of generating an error. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- V1->V2: - Add comment and update changelog, per code review feedback - Rebase + retest on net-next net/netfilter/nf_conntrack_netlink.c | 17 + 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index e8f704a6..891f02a 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1503,14 +1503,23 @@ static int ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *helpinfo = NULL; int err; - /* don't change helper of sibling connections */ - if (ct->master) - return -EBUSY; - err = ctnetlink_parse_help(cda[CTA_HELP], , ); if (err < 0) return err; + /* don't change helper of sibling connections */ + if (ct->master) { + /* If we try to change the helper to the same thing twice, +* treat the second attempt as a no-op instead of returning +* an error. +*/ + if (help && help->helper && + !strcmp(help->helper->name, helpname)) + return 0; + else + return -EBUSY; + } + if (!strcmp(helpname, "")) { if (help && help->helper) { /* we had a helper before ... */ -- 2.7.4
[PATCH V2 2/2] netfilter: ctnetlink: Fix regression in CTA_HELP processing
Prior to Linux 4.4, it was usually harmless to send a CTA_HELP attribute containing the name of the current helper. That is no longer the case: as of Linux 4.4, if ctnetlink_change_helper() returns an error from the ct->master check, processing of the request will fail, skipping the NFQA_EXP attribute (if present). This patch changes the behavior to improve compatibility with user programs that expect the kernel interface to work the way it did prior to Linux 4.4. If a user program specifies CTA_HELP but the argument matches the current conntrack helper name, ignore it instead of generating an error. Signed-off-by: Kevin Cernekee --- V1->V2: - Add comment and update changelog, per code review feedback - Rebase + retest on net-next net/netfilter/nf_conntrack_netlink.c | 17 + 1 file changed, 13 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index e8f704a6..891f02a 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1503,14 +1503,23 @@ static int ctnetlink_change_helper(struct nf_conn *ct, struct nlattr *helpinfo = NULL; int err; - /* don't change helper of sibling connections */ - if (ct->master) - return -EBUSY; - err = ctnetlink_parse_help(cda[CTA_HELP], , ); if (err < 0) return err; + /* don't change helper of sibling connections */ + if (ct->master) { + /* If we try to change the helper to the same thing twice, +* treat the second attempt as a no-op instead of returning +* an error. +*/ + if (help && help->helper && + !strcmp(help->helper->name, helpname)) + return 0; + else + return -EBUSY; + } + if (!strcmp(helpname, "")) { if (help && help->helper) { /* we had a helper before ... */ -- 2.7.4
[PATCH V2 1/2] netfilter: ctnetlink: Fix regression in CTA_STATUS processing
The libnetfilter_conntrack userland library always sets IPS_CONFIRMED when building a CTA_STATUS attribute. If this toggles the bit from 0->1, the parser will return an error. On Linux 4.4+ this will cause any NFQA_EXP attribute in the packet to be ignored. This breaks conntrackd's userland helpers because they operate on unconfirmed connections. Instead of returning -EBUSY if the user program asks to modify an unchangeable bit, simply ignore the change. Also, fix the logic so that user programs are allowed to clear the bits that they are allowed to change. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- V1->V2: - Create a new ctnetlink_update_status() function, per code review feedback - Add comment and update changelog, per code review feedback - Rebase + retest on net-next (Note that the original patch 1/3, which fixed a related problem on CTA_TIMEOUT, is only needed on old kernels like 4.4.) include/uapi/linux/netfilter/nf_conntrack_common.h | 4 net/netfilter/nf_conntrack_netlink.c | 27 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h index 6d074d1..6a8e33d 100644 --- a/include/uapi/linux/netfilter/nf_conntrack_common.h +++ b/include/uapi/linux/netfilter/nf_conntrack_common.h @@ -82,6 +82,10 @@ enum ip_conntrack_status { IPS_DYING_BIT = 9, IPS_DYING = (1 << IPS_DYING_BIT), + /* Bits that cannot be altered from userland. */ + IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK | +IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING), + /* Connection has fixed timeout. */ IPS_FIXED_TIMEOUT_BIT = 10, IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 2754045..e8f704a6 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1446,6 +1446,31 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[]) } static int +ctnetlink_update_status(struct nf_conn *ct, const struct nlattr * const cda[]) +{ + unsigned long d; + unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS])); + d = ct->status ^ status; + + if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) + /* SEEN_REPLY bit can only be set */ + return -EBUSY; + + if (d & IPS_ASSURED && !(status & IPS_ASSURED)) + /* ASSURED bit can only be set */ + return -EBUSY; + + /* This check is less strict than ctnetlink_change_status() +* because callers often flip IPS_EXPECTED bits when sending +* an NFQA_CT attribute to the kernel. So ignore the +* unchangeable bits but do not error out. +*/ + ct->status = (status & ~IPS_UNCHANGEABLE_MASK) | +(ct->status & IPS_UNCHANGEABLE_MASK); + return 0; +} + +static int ctnetlink_setup_nat(struct nf_conn *ct, const struct nlattr * const cda[]) { #ifdef CONFIG_NF_NAT_NEEDED @@ -2280,7 +2305,7 @@ ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) return err; } if (cda[CTA_STATUS]) { - err = ctnetlink_change_status(ct, cda); + err = ctnetlink_update_status(ct, cda); if (err < 0) return err; } -- 2.7.4
[PATCH V2 1/2] netfilter: ctnetlink: Fix regression in CTA_STATUS processing
The libnetfilter_conntrack userland library always sets IPS_CONFIRMED when building a CTA_STATUS attribute. If this toggles the bit from 0->1, the parser will return an error. On Linux 4.4+ this will cause any NFQA_EXP attribute in the packet to be ignored. This breaks conntrackd's userland helpers because they operate on unconfirmed connections. Instead of returning -EBUSY if the user program asks to modify an unchangeable bit, simply ignore the change. Also, fix the logic so that user programs are allowed to clear the bits that they are allowed to change. Signed-off-by: Kevin Cernekee --- V1->V2: - Create a new ctnetlink_update_status() function, per code review feedback - Add comment and update changelog, per code review feedback - Rebase + retest on net-next (Note that the original patch 1/3, which fixed a related problem on CTA_TIMEOUT, is only needed on old kernels like 4.4.) include/uapi/linux/netfilter/nf_conntrack_common.h | 4 net/netfilter/nf_conntrack_netlink.c | 27 +- 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h index 6d074d1..6a8e33d 100644 --- a/include/uapi/linux/netfilter/nf_conntrack_common.h +++ b/include/uapi/linux/netfilter/nf_conntrack_common.h @@ -82,6 +82,10 @@ enum ip_conntrack_status { IPS_DYING_BIT = 9, IPS_DYING = (1 << IPS_DYING_BIT), + /* Bits that cannot be altered from userland. */ + IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK | +IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING), + /* Connection has fixed timeout. */ IPS_FIXED_TIMEOUT_BIT = 10, IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 2754045..e8f704a6 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1446,6 +1446,31 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[]) } static int +ctnetlink_update_status(struct nf_conn *ct, const struct nlattr * const cda[]) +{ + unsigned long d; + unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS])); + d = ct->status ^ status; + + if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) + /* SEEN_REPLY bit can only be set */ + return -EBUSY; + + if (d & IPS_ASSURED && !(status & IPS_ASSURED)) + /* ASSURED bit can only be set */ + return -EBUSY; + + /* This check is less strict than ctnetlink_change_status() +* because callers often flip IPS_EXPECTED bits when sending +* an NFQA_CT attribute to the kernel. So ignore the +* unchangeable bits but do not error out. +*/ + ct->status = (status & ~IPS_UNCHANGEABLE_MASK) | +(ct->status & IPS_UNCHANGEABLE_MASK); + return 0; +} + +static int ctnetlink_setup_nat(struct nf_conn *ct, const struct nlattr * const cda[]) { #ifdef CONFIG_NF_NAT_NEEDED @@ -2280,7 +2305,7 @@ ctnetlink_glue_parse_ct(const struct nlattr *cda[], struct nf_conn *ct) return err; } if (cda[CTA_STATUS]) { - err = ctnetlink_change_status(ct, cda); + err = ctnetlink_update_status(ct, cda); if (err < 0) return err; } -- 2.7.4
[PATCH 1/4] xfrm: Constify xfrm_user arguments and xfrm_mgr callback APIs
This provides a better sense of the data flow and inputs/outputs. No change to code size or functionality. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- include/net/xfrm.h | 36 -- net/key/af_key.c | 34 +++-- net/xfrm/xfrm_policy.c | 8 +- net/xfrm/xfrm_state.c | 2 +- net/xfrm/xfrm_user.c | 342 + 5 files changed, 253 insertions(+), 169 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 31947b9c21d6..34298d78ba45 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -228,7 +228,7 @@ struct xfrm_state { void*data; }; -static inline struct net *xs_net(struct xfrm_state *x) +static inline struct net *xs_net(const struct xfrm_state *x) { return read_pnet(>xs_net); } @@ -587,12 +587,23 @@ struct xfrm_migrate { struct xfrm_mgr { struct list_headlist; char*id; - int (*notify)(struct xfrm_state *x, const struct km_event *c); - int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp); - struct xfrm_policy *(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir); - int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); - int (*notify_policy)(struct xfrm_policy *x, int dir, const struct km_event *c); - int (*report)(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); + int (*notify)(const struct xfrm_state *x, + const struct km_event *c); + int (*acquire)(struct xfrm_state *x, + const struct xfrm_tmpl *, + const struct xfrm_policy *xp); + struct xfrm_policy *(*compile_policy)(struct sock *sk, + int opt, u8 *data, + int len, int *dir); + int (*new_mapping)(struct xfrm_state *x, + const xfrm_address_t *ipaddr, + __be16 sport); + int (*notify_policy)(const struct xfrm_policy *x, +int dir, +const struct km_event *c); + int (*report)(struct net *net, u8 proto, + const struct xfrm_selector *sel, + const xfrm_address_t *addr); int (*migrate)(const struct xfrm_selector *sel, u8 dir, u8 type, const struct xfrm_migrate *m, @@ -1432,7 +1443,7 @@ static inline void xfrm_sysctl_fini(struct net *net) void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, struct xfrm_address_filter *filter); int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, - int (*func)(struct xfrm_state *, int, void*), void *); + int (*func)(const struct xfrm_state *, int, void*), void *); void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net); struct xfrm_state *xfrm_state_alloc(struct net *net); struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr, @@ -1584,13 +1595,13 @@ struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp); void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type); int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, -int (*func)(struct xfrm_policy *, int, int, void*), +int (*func)(const struct xfrm_policy *, int, int, void*), void *); void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net); int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, int dir, - struct xfrm_selector *sel, + const struct xfrm_selector *sel, struct xfrm_sec_ctx *ctx, int delete, int *err); struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, @@ -1695,7 +1706,7 @@ static inline int xfrm_acquire_is_on(struct net *net) } #endif -static inline int aead_len(struct xfrm_algo_aead *alg) +static inline int aead_len(const struct xfrm_algo_aead *alg) { return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); } @@ -1710,7 +1721,8 @@ s
[PATCH 0/4] Make xfrm usable by 32-bit programs
Several of the xfrm netlink and setsockopt() interfaces are not usable from a 32-bit binary running on a 64-bit kernel due to struct padding differences. This has been the case for many, many years[0]. This patch series deprecates the broken netlink messages and replaces them with packed structs that are compatible between 64-bit and 32-bit programs. It retains support for legacy user programs (i.e. anything that is currently working today), and allows legacy support to be compiled out via CONFIG_XFRM_USER_LEGACY if it becomes unnecessary in the future. Earlier attempts at fixing the problem had implemented a compat layer. A compat layer is helpful because it avoids the need to recompile old user binaries, but there are many challenges involved in implementing it. I believe a compat layer is of limited value in this instance because anybody who really needed to solve the problem without recompiling their binaries has almost certainly found another solution in the ~7 years since the compat patches were first proposed. A benefit of this approach is that long-term, the broken netlink messages will no longer be used. A drawback is that in the short term, user programs that want to adopt the new message formats will require a modern kernel. Projects like strongSwan and iproute2 bundle the xfrm.h header inside their own source trees, so they will need to make a judgment call on when to remove support for kernels that do not support the new messages. And programs built against the new kernel headers will not work on old kernels. (Perhaps this is an argument for naming the new messages _NEW, rather than renaming the old messages to _LEGACY.) The following netlink messages are affected: XFRM_MSG_NEWSA XFRM_MSG_UPDSA XFRM_MSG_DELSA XFRM_MSG_GETSA XFRM_MSG_NEWPOLICY XFRM_MSG_UPDPOLICY XFRM_MSG_DELPOLICY XFRM_MSG_GETPOLICY XFRM_MSG_ALLOCSPI XFRM_MSG_ACQUIRE XFRM_MSG_EXPIRE XFRM_MSG_POLEXPIRE The following setsockopt() settings are affected: IP_XFRM_POLICY IPV6_XFRM_POLICY The root cause of the problem involves padding and alignment incompatibilities in the following structs: xfrm_usersa_info 220 bytes on i386 -> 224 bytes on amd64 xfrm_userpolicy_info 164 -> 168 xfrm_userspi_info 228 -> 232, offset mismatch on min xfrm_user_acquire 276 -> 280, offset mismatch on aalgos xfrm_user_expire 224 -> 232, offset mismatch on hard xfrm_user_polexpire 168 -> 176, offset mismatch on hard Most xfrm netlink messages consist of an xfrm_* struct followed by additional attributes (struct nlattr TLV), so even cases where the struct layout (sans padding) is identical will result in incompatible messages. Some possible tweaks to this approach: a) Name the new messages _NEW instead of renaming the old messages _LEGACY. This fixes the "new binary on old kernel" problem, but it means that callers need to change every call site in their programs to explicitly request the new interface. b) Tweak xfrm.h so that user programs build against the legacy interfaces by default, but can alter that behavior using a #define flag. Maybe in a few years, assume that everyone is running a modern kernel and make the new interface the default. [0] https://www.spinics.net/lists/netdev/msg126176.html Kevin Cernekee (4): xfrm: Constify xfrm_user arguments and xfrm_mgr callback APIs xfrm_user: Allow common functions to be called from another file xfrm_user: Initial commit of xfrm_user_legacy.c xfrm_user: Add new 32/64-agnostic netlink messages include/net/xfrm.h | 36 +- include/uapi/linux/xfrm.h | 152 -- net/key/af_key.c| 34 +- net/xfrm/Kconfig| 14 + net/xfrm/Makefile |8 +- net/xfrm/xfrm_policy.c |8 +- net/xfrm/xfrm_state.c |2 +- net/xfrm/xfrm_user.c| 587 +- net/xfrm/xfrm_user.h| 165 +++ net/xfrm/xfrm_user_legacy.c | 1140 +++ security/selinux/nlmsgtab.c | 61 ++- 11 files changed, 1890 insertions(+), 317 deletions(-) create mode 100644 net/xfrm/xfrm_user.h create mode 100644 net/xfrm/xfrm_user_legacy.c -- 2.11.0.483.g087da7b7c-goog
[PATCH 0/4] Make xfrm usable by 32-bit programs
Several of the xfrm netlink and setsockopt() interfaces are not usable from a 32-bit binary running on a 64-bit kernel due to struct padding differences. This has been the case for many, many years[0]. This patch series deprecates the broken netlink messages and replaces them with packed structs that are compatible between 64-bit and 32-bit programs. It retains support for legacy user programs (i.e. anything that is currently working today), and allows legacy support to be compiled out via CONFIG_XFRM_USER_LEGACY if it becomes unnecessary in the future. Earlier attempts at fixing the problem had implemented a compat layer. A compat layer is helpful because it avoids the need to recompile old user binaries, but there are many challenges involved in implementing it. I believe a compat layer is of limited value in this instance because anybody who really needed to solve the problem without recompiling their binaries has almost certainly found another solution in the ~7 years since the compat patches were first proposed. A benefit of this approach is that long-term, the broken netlink messages will no longer be used. A drawback is that in the short term, user programs that want to adopt the new message formats will require a modern kernel. Projects like strongSwan and iproute2 bundle the xfrm.h header inside their own source trees, so they will need to make a judgment call on when to remove support for kernels that do not support the new messages. And programs built against the new kernel headers will not work on old kernels. (Perhaps this is an argument for naming the new messages _NEW, rather than renaming the old messages to _LEGACY.) The following netlink messages are affected: XFRM_MSG_NEWSA XFRM_MSG_UPDSA XFRM_MSG_DELSA XFRM_MSG_GETSA XFRM_MSG_NEWPOLICY XFRM_MSG_UPDPOLICY XFRM_MSG_DELPOLICY XFRM_MSG_GETPOLICY XFRM_MSG_ALLOCSPI XFRM_MSG_ACQUIRE XFRM_MSG_EXPIRE XFRM_MSG_POLEXPIRE The following setsockopt() settings are affected: IP_XFRM_POLICY IPV6_XFRM_POLICY The root cause of the problem involves padding and alignment incompatibilities in the following structs: xfrm_usersa_info 220 bytes on i386 -> 224 bytes on amd64 xfrm_userpolicy_info 164 -> 168 xfrm_userspi_info 228 -> 232, offset mismatch on min xfrm_user_acquire 276 -> 280, offset mismatch on aalgos xfrm_user_expire 224 -> 232, offset mismatch on hard xfrm_user_polexpire 168 -> 176, offset mismatch on hard Most xfrm netlink messages consist of an xfrm_* struct followed by additional attributes (struct nlattr TLV), so even cases where the struct layout (sans padding) is identical will result in incompatible messages. Some possible tweaks to this approach: a) Name the new messages _NEW instead of renaming the old messages _LEGACY. This fixes the "new binary on old kernel" problem, but it means that callers need to change every call site in their programs to explicitly request the new interface. b) Tweak xfrm.h so that user programs build against the legacy interfaces by default, but can alter that behavior using a #define flag. Maybe in a few years, assume that everyone is running a modern kernel and make the new interface the default. [0] https://www.spinics.net/lists/netdev/msg126176.html Kevin Cernekee (4): xfrm: Constify xfrm_user arguments and xfrm_mgr callback APIs xfrm_user: Allow common functions to be called from another file xfrm_user: Initial commit of xfrm_user_legacy.c xfrm_user: Add new 32/64-agnostic netlink messages include/net/xfrm.h | 36 +- include/uapi/linux/xfrm.h | 152 -- net/key/af_key.c| 34 +- net/xfrm/Kconfig| 14 + net/xfrm/Makefile |8 +- net/xfrm/xfrm_policy.c |8 +- net/xfrm/xfrm_state.c |2 +- net/xfrm/xfrm_user.c| 587 +- net/xfrm/xfrm_user.h| 165 +++ net/xfrm/xfrm_user_legacy.c | 1140 +++ security/selinux/nlmsgtab.c | 61 ++- 11 files changed, 1890 insertions(+), 317 deletions(-) create mode 100644 net/xfrm/xfrm_user.h create mode 100644 net/xfrm/xfrm_user_legacy.c -- 2.11.0.483.g087da7b7c-goog
[PATCH 1/4] xfrm: Constify xfrm_user arguments and xfrm_mgr callback APIs
This provides a better sense of the data flow and inputs/outputs. No change to code size or functionality. Signed-off-by: Kevin Cernekee --- include/net/xfrm.h | 36 -- net/key/af_key.c | 34 +++-- net/xfrm/xfrm_policy.c | 8 +- net/xfrm/xfrm_state.c | 2 +- net/xfrm/xfrm_user.c | 342 + 5 files changed, 253 insertions(+), 169 deletions(-) diff --git a/include/net/xfrm.h b/include/net/xfrm.h index 31947b9c21d6..34298d78ba45 100644 --- a/include/net/xfrm.h +++ b/include/net/xfrm.h @@ -228,7 +228,7 @@ struct xfrm_state { void*data; }; -static inline struct net *xs_net(struct xfrm_state *x) +static inline struct net *xs_net(const struct xfrm_state *x) { return read_pnet(>xs_net); } @@ -587,12 +587,23 @@ struct xfrm_migrate { struct xfrm_mgr { struct list_headlist; char*id; - int (*notify)(struct xfrm_state *x, const struct km_event *c); - int (*acquire)(struct xfrm_state *x, struct xfrm_tmpl *, struct xfrm_policy *xp); - struct xfrm_policy *(*compile_policy)(struct sock *sk, int opt, u8 *data, int len, int *dir); - int (*new_mapping)(struct xfrm_state *x, xfrm_address_t *ipaddr, __be16 sport); - int (*notify_policy)(struct xfrm_policy *x, int dir, const struct km_event *c); - int (*report)(struct net *net, u8 proto, struct xfrm_selector *sel, xfrm_address_t *addr); + int (*notify)(const struct xfrm_state *x, + const struct km_event *c); + int (*acquire)(struct xfrm_state *x, + const struct xfrm_tmpl *, + const struct xfrm_policy *xp); + struct xfrm_policy *(*compile_policy)(struct sock *sk, + int opt, u8 *data, + int len, int *dir); + int (*new_mapping)(struct xfrm_state *x, + const xfrm_address_t *ipaddr, + __be16 sport); + int (*notify_policy)(const struct xfrm_policy *x, +int dir, +const struct km_event *c); + int (*report)(struct net *net, u8 proto, + const struct xfrm_selector *sel, + const xfrm_address_t *addr); int (*migrate)(const struct xfrm_selector *sel, u8 dir, u8 type, const struct xfrm_migrate *m, @@ -1432,7 +1443,7 @@ static inline void xfrm_sysctl_fini(struct net *net) void xfrm_state_walk_init(struct xfrm_state_walk *walk, u8 proto, struct xfrm_address_filter *filter); int xfrm_state_walk(struct net *net, struct xfrm_state_walk *walk, - int (*func)(struct xfrm_state *, int, void*), void *); + int (*func)(const struct xfrm_state *, int, void*), void *); void xfrm_state_walk_done(struct xfrm_state_walk *walk, struct net *net); struct xfrm_state *xfrm_state_alloc(struct net *net); struct xfrm_state *xfrm_state_find(const xfrm_address_t *daddr, @@ -1584,13 +1595,13 @@ struct xfrm_policy *xfrm_policy_alloc(struct net *net, gfp_t gfp); void xfrm_policy_walk_init(struct xfrm_policy_walk *walk, u8 type); int xfrm_policy_walk(struct net *net, struct xfrm_policy_walk *walk, -int (*func)(struct xfrm_policy *, int, int, void*), +int (*func)(const struct xfrm_policy *, int, int, void*), void *); void xfrm_policy_walk_done(struct xfrm_policy_walk *walk, struct net *net); int xfrm_policy_insert(int dir, struct xfrm_policy *policy, int excl); struct xfrm_policy *xfrm_policy_bysel_ctx(struct net *net, u32 mark, u8 type, int dir, - struct xfrm_selector *sel, + const struct xfrm_selector *sel, struct xfrm_sec_ctx *ctx, int delete, int *err); struct xfrm_policy *xfrm_policy_byid(struct net *net, u32 mark, u8, int dir, @@ -1695,7 +1706,7 @@ static inline int xfrm_acquire_is_on(struct net *net) } #endif -static inline int aead_len(struct xfrm_algo_aead *alg) +static inline int aead_len(const struct xfrm_algo_aead *alg) { return sizeof(*alg) + ((alg->alg_key_len + 7) / 8); } @@ -1710,7 +1721,8 @@ static inline int xfrm_alg_au
[PATCH 2/4] xfrm_user: Allow common functions to be called from another file
xfrm_user_legacy.c will need to call a few common functions. Make sure them have an "xfrm_" prefix, and declare them in a new xfrm_user.h header. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- net/xfrm/xfrm_user.c | 147 +-- net/xfrm/xfrm_user.h | 90 +++ 2 files changed, 138 insertions(+), 99 deletions(-) create mode 100644 net/xfrm/xfrm_user.h diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index ed389aad4994..4d733f02c3a1 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -32,6 +32,7 @@ #include #endif #include +#include "xfrm_user.h" static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) { @@ -100,7 +101,7 @@ static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type, *addrp = nla_data(rt); } -static inline int verify_sec_ctx_len(struct nlattr **attrs) +int xfrm_verify_sec_ctx_len(struct nlattr **attrs) { struct nlattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_user_sec_ctx *uctx; @@ -148,8 +149,8 @@ static inline int verify_replay(const struct xfrm_usersa_info *p, return 0; } -static int verify_newsa_info(const struct xfrm_usersa_info *p, -struct nlattr **attrs) +int xfrm_verify_newsa_info(const struct xfrm_usersa_info *p, + struct nlattr **attrs) { int err; @@ -241,7 +242,7 @@ static int verify_newsa_info(const struct xfrm_usersa_info *p, goto out; if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP))) goto out; - if ((err = verify_sec_ctx_len(attrs))) + if ((err = xfrm_verify_sec_ctx_len(attrs))) goto out; if ((err = verify_replay(p, attrs))) goto out; @@ -460,17 +461,6 @@ static int xfrm_alloc_replay_state_esn( return 0; } -static inline int xfrm_user_sec_ctx_size(const struct xfrm_sec_ctx *xfrm_ctx) -{ - int len = 0; - - if (xfrm_ctx) { - len += sizeof(struct xfrm_user_sec_ctx); - len += xfrm_ctx->ctx_len; - } - return len; -} - static void copy_from_user_state(struct xfrm_state *x, const struct xfrm_usersa_info *p) { @@ -537,10 +527,10 @@ static void xfrm_update_ae_params(struct xfrm_state *x, x->replay_maxdiff = nla_get_u32(rt); } -static struct xfrm_state *xfrm_state_construct(struct net *net, - const struct xfrm_usersa_info *p, - struct nlattr **attrs, - int *errp) +struct xfrm_state *xfrm_state_construct(struct net *net, + const struct xfrm_usersa_info *p, + struct nlattr **attrs, + int *errp) { struct xfrm_state *x = xfrm_state_alloc(net); int err = -ENOMEM; @@ -634,7 +624,7 @@ static int xfrm_add_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, int err; struct km_event c; - err = verify_newsa_info(p, attrs); + err = xfrm_verify_newsa_info(p, attrs); if (err) return err; @@ -666,10 +656,10 @@ static int xfrm_add_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, return err; } -static struct xfrm_state *xfrm_user_state_lookup(struct net *net, -const struct xfrm_usersa_id *p, -struct nlattr **attrs, -int *errp) +struct xfrm_state *xfrm_user_state_lookup(struct net *net, + const struct xfrm_usersa_id *p, + struct nlattr **attrs, + int *errp) { struct xfrm_state *x = NULL; struct xfrm_mark m; @@ -757,14 +747,7 @@ static void copy_to_user_state(const struct xfrm_state *x, p->seq = x->km.seq; } -struct xfrm_dump_info { - struct sk_buff *in_skb; - struct sk_buff *out_skb; - u32 nlmsg_seq; - u16 nlmsg_flags; -}; - -static int copy_sec_ctx(const struct xfrm_sec_ctx *s, struct sk_buff *skb) +int xfrm_copy_sec_ctx(const struct xfrm_sec_ctx *s, struct sk_buff *skb) { struct xfrm_user_sec_ctx *uctx; struct nlattr *attr; @@ -785,8 +768,8 @@ static int copy_sec_ctx(const struct xfrm_sec_ctx *s, struct sk_buff *skb) return 0; } -static int copy_to_user_auth(const struct xfrm_algo_auth *auth, -struct sk_buff *skb) +int xfrm_copy_to_user_auth(const struct xfrm_algo_auth *auth, + struct sk_buff *skb) { struct xfrm_algo *algo; struct nlatt
[PATCH 2/4] xfrm_user: Allow common functions to be called from another file
xfrm_user_legacy.c will need to call a few common functions. Make sure them have an "xfrm_" prefix, and declare them in a new xfrm_user.h header. Signed-off-by: Kevin Cernekee --- net/xfrm/xfrm_user.c | 147 +-- net/xfrm/xfrm_user.h | 90 +++ 2 files changed, 138 insertions(+), 99 deletions(-) create mode 100644 net/xfrm/xfrm_user.h diff --git a/net/xfrm/xfrm_user.c b/net/xfrm/xfrm_user.c index ed389aad4994..4d733f02c3a1 100644 --- a/net/xfrm/xfrm_user.c +++ b/net/xfrm/xfrm_user.c @@ -32,6 +32,7 @@ #include #endif #include +#include "xfrm_user.h" static int verify_one_alg(struct nlattr **attrs, enum xfrm_attr_type_t type) { @@ -100,7 +101,7 @@ static void verify_one_addr(struct nlattr **attrs, enum xfrm_attr_type_t type, *addrp = nla_data(rt); } -static inline int verify_sec_ctx_len(struct nlattr **attrs) +int xfrm_verify_sec_ctx_len(struct nlattr **attrs) { struct nlattr *rt = attrs[XFRMA_SEC_CTX]; struct xfrm_user_sec_ctx *uctx; @@ -148,8 +149,8 @@ static inline int verify_replay(const struct xfrm_usersa_info *p, return 0; } -static int verify_newsa_info(const struct xfrm_usersa_info *p, -struct nlattr **attrs) +int xfrm_verify_newsa_info(const struct xfrm_usersa_info *p, + struct nlattr **attrs) { int err; @@ -241,7 +242,7 @@ static int verify_newsa_info(const struct xfrm_usersa_info *p, goto out; if ((err = verify_one_alg(attrs, XFRMA_ALG_COMP))) goto out; - if ((err = verify_sec_ctx_len(attrs))) + if ((err = xfrm_verify_sec_ctx_len(attrs))) goto out; if ((err = verify_replay(p, attrs))) goto out; @@ -460,17 +461,6 @@ static int xfrm_alloc_replay_state_esn( return 0; } -static inline int xfrm_user_sec_ctx_size(const struct xfrm_sec_ctx *xfrm_ctx) -{ - int len = 0; - - if (xfrm_ctx) { - len += sizeof(struct xfrm_user_sec_ctx); - len += xfrm_ctx->ctx_len; - } - return len; -} - static void copy_from_user_state(struct xfrm_state *x, const struct xfrm_usersa_info *p) { @@ -537,10 +527,10 @@ static void xfrm_update_ae_params(struct xfrm_state *x, x->replay_maxdiff = nla_get_u32(rt); } -static struct xfrm_state *xfrm_state_construct(struct net *net, - const struct xfrm_usersa_info *p, - struct nlattr **attrs, - int *errp) +struct xfrm_state *xfrm_state_construct(struct net *net, + const struct xfrm_usersa_info *p, + struct nlattr **attrs, + int *errp) { struct xfrm_state *x = xfrm_state_alloc(net); int err = -ENOMEM; @@ -634,7 +624,7 @@ static int xfrm_add_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, int err; struct km_event c; - err = verify_newsa_info(p, attrs); + err = xfrm_verify_newsa_info(p, attrs); if (err) return err; @@ -666,10 +656,10 @@ static int xfrm_add_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, return err; } -static struct xfrm_state *xfrm_user_state_lookup(struct net *net, -const struct xfrm_usersa_id *p, -struct nlattr **attrs, -int *errp) +struct xfrm_state *xfrm_user_state_lookup(struct net *net, + const struct xfrm_usersa_id *p, + struct nlattr **attrs, + int *errp) { struct xfrm_state *x = NULL; struct xfrm_mark m; @@ -757,14 +747,7 @@ static void copy_to_user_state(const struct xfrm_state *x, p->seq = x->km.seq; } -struct xfrm_dump_info { - struct sk_buff *in_skb; - struct sk_buff *out_skb; - u32 nlmsg_seq; - u16 nlmsg_flags; -}; - -static int copy_sec_ctx(const struct xfrm_sec_ctx *s, struct sk_buff *skb) +int xfrm_copy_sec_ctx(const struct xfrm_sec_ctx *s, struct sk_buff *skb) { struct xfrm_user_sec_ctx *uctx; struct nlattr *attr; @@ -785,8 +768,8 @@ static int copy_sec_ctx(const struct xfrm_sec_ctx *s, struct sk_buff *skb) return 0; } -static int copy_to_user_auth(const struct xfrm_algo_auth *auth, -struct sk_buff *skb) +int xfrm_copy_to_user_auth(const struct xfrm_algo_auth *auth, + struct sk_buff *skb) { struct xfrm_algo *algo; struct nlattr *nla; @@ -837,7 +820,7 @@ static int copy_
[PATCH 4/4] xfrm_user: Add new 32/64-agnostic netlink messages
Add several new message types to address longstanding 32-bit/64-bit compatibility issues. Use xfrm_user_legacy to handle the existing message types, which will retain the old IDs for compatibility with existing binaries. For user->kernel messages, the nlmsg_type will determine whether to use the old format or the new format (for both requests and replies). For kernel->user multicasts, both types will be sent. setsockopt() will deduce the format from the length. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- include/uapi/linux/xfrm.h | 152 ++- net/xfrm/xfrm_user.c| 136 --- net/xfrm/xfrm_user.h| 75 net/xfrm/xfrm_user_legacy.c | 169 security/selinux/nlmsgtab.c | 61 +--- 5 files changed, 466 insertions(+), 127 deletions(-) diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h index 1fc62b239f1b..ae5f97681989 100644 --- a/include/uapi/linux/xfrm.h +++ b/include/uapi/linux/xfrm.h @@ -1,6 +1,7 @@ #ifndef _LINUX_XFRM_H #define _LINUX_XFRM_H +#include #include #include @@ -157,34 +158,34 @@ enum { enum { XFRM_MSG_BASE = 0x10, - XFRM_MSG_NEWSA = 0x10, -#define XFRM_MSG_NEWSA XFRM_MSG_NEWSA - XFRM_MSG_DELSA, -#define XFRM_MSG_DELSA XFRM_MSG_DELSA - XFRM_MSG_GETSA, -#define XFRM_MSG_GETSA XFRM_MSG_GETSA - - XFRM_MSG_NEWPOLICY, -#define XFRM_MSG_NEWPOLICY XFRM_MSG_NEWPOLICY - XFRM_MSG_DELPOLICY, -#define XFRM_MSG_DELPOLICY XFRM_MSG_DELPOLICY - XFRM_MSG_GETPOLICY, -#define XFRM_MSG_GETPOLICY XFRM_MSG_GETPOLICY - - XFRM_MSG_ALLOCSPI, -#define XFRM_MSG_ALLOCSPI XFRM_MSG_ALLOCSPI - XFRM_MSG_ACQUIRE, -#define XFRM_MSG_ACQUIRE XFRM_MSG_ACQUIRE - XFRM_MSG_EXPIRE, -#define XFRM_MSG_EXPIRE XFRM_MSG_EXPIRE - - XFRM_MSG_UPDPOLICY, -#define XFRM_MSG_UPDPOLICY XFRM_MSG_UPDPOLICY - XFRM_MSG_UPDSA, -#define XFRM_MSG_UPDSA XFRM_MSG_UPDSA - - XFRM_MSG_POLEXPIRE, -#define XFRM_MSG_POLEXPIRE XFRM_MSG_POLEXPIRE + XFRM_MSG_NEWSA_LEGACY = 0x10, +#define XFRM_MSG_NEWSA_LEGACY XFRM_MSG_NEWSA_LEGACY + XFRM_MSG_DELSA_LEGACY, +#define XFRM_MSG_DELSA_LEGACY XFRM_MSG_DELSA_LEGACY + XFRM_MSG_GETSA_LEGACY, +#define XFRM_MSG_GETSA_LEGACY XFRM_MSG_GETSA_LEGACY + + XFRM_MSG_NEWPOLICY_LEGACY, +#define XFRM_MSG_NEWPOLICY_LEGACY XFRM_MSG_NEWPOLICY_LEGACY + XFRM_MSG_DELPOLICY_LEGACY, +#define XFRM_MSG_DELPOLICY_LEGACY XFRM_MSG_DELPOLICY_LEGACY + XFRM_MSG_GETPOLICY_LEGACY, +#define XFRM_MSG_GETPOLICY_LEGACY XFRM_MSG_GETPOLICY_LEGACY + + XFRM_MSG_ALLOCSPI_LEGACY, +#define XFRM_MSG_ALLOCSPI_LEGACY XFRM_MSG_ALLOCSPI_LEGACY + XFRM_MSG_ACQUIRE_LEGACY, +#define XFRM_MSG_ACQUIRE_LEGACY XFRM_MSG_ACQUIRE_LEGACY + XFRM_MSG_EXPIRE_LEGACY, +#define XFRM_MSG_EXPIRE_LEGACY XFRM_MSG_EXPIRE_LEGACY + + XFRM_MSG_UPDPOLICY_LEGACY, +#define XFRM_MSG_UPDPOLICY_LEGACY XFRM_MSG_UPDPOLICY_LEGACY + XFRM_MSG_UPDSA_LEGACY, +#define XFRM_MSG_UPDSA_LEGACY XFRM_MSG_UPDSA_LEGACY + + XFRM_MSG_POLEXPIRE_LEGACY, +#define XFRM_MSG_POLEXPIRE_LEGACY XFRM_MSG_POLEXPIRE_LEGACY XFRM_MSG_FLUSHSA, #define XFRM_MSG_FLUSHSA XFRM_MSG_FLUSHSA @@ -214,6 +215,34 @@ enum { XFRM_MSG_MAPPING, #define XFRM_MSG_MAPPING XFRM_MSG_MAPPING + + XFRM_MSG_ALLOCSPI, +#define XFRM_MSG_ALLOCSPI XFRM_MSG_ALLOCSPI + XFRM_MSG_ACQUIRE, +#define XFRM_MSG_ACQUIRE XFRM_MSG_ACQUIRE + XFRM_MSG_EXPIRE, +#define XFRM_MSG_EXPIRE XFRM_MSG_EXPIRE + XFRM_MSG_POLEXPIRE, +#define XFRM_MSG_POLEXPIRE XFRM_MSG_POLEXPIRE + + XFRM_MSG_NEWSA, +#define XFRM_MSG_NEWSA XFRM_MSG_NEWSA + XFRM_MSG_UPDSA, +#define XFRM_MSG_UPDSA XFRM_MSG_UPDSA + XFRM_MSG_DELSA, +#define XFRM_MSG_DELSA XFRM_MSG_DELSA + XFRM_MSG_GETSA, +#define XFRM_MSG_GETSA XFRM_MSG_GETSA + + XFRM_MSG_NEWPOLICY, +#define XFRM_MSG_NEWPOLICY XFRM_MSG_NEWPOLICY + XFRM_MSG_UPDPOLICY, +#define XFRM_MSG_UPDPOLICY XFRM_MSG_UPDPOLICY + XFRM_MSG_DELPOLICY, +#define XFRM_MSG_DELPOLICY XFRM_MSG_DELPOLICY + XFRM_MSG_GETPOLICY, +#define XFRM_MSG_GETPOLICY XFRM_MSG_GETPOLICY + __XFRM_MSG_MAX }; #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) @@ -221,7 +250,7 @@ enum { #define XFRM_NR_MSGTYPES (XFRM_MSG_MAX + 1 - XFRM_MSG_BASE) /* - * Generic LSM security context for comunicating to user space + * Generic LSM security context for communicating to user space * NOTE: Same format as sadb_x_sec_ctx */ struct xfrm_user_sec_ctx { @@ -357,6 +386,22 @@ struct xfrmu_spdhthresh { __u8 rbits; }; +/* Legacy structs are incompatible between 32-bit and 64-bit. */ +struct xfrm_usersa_info_legacy { + struct xfrm_selectorsel; + struct xfrm_id id; + xfrm_address_t saddr; + struct xfrm_lifetime_cfglft; + struct xfrm_lifetime_cur
[PATCH 4/4] xfrm_user: Add new 32/64-agnostic netlink messages
Add several new message types to address longstanding 32-bit/64-bit compatibility issues. Use xfrm_user_legacy to handle the existing message types, which will retain the old IDs for compatibility with existing binaries. For user->kernel messages, the nlmsg_type will determine whether to use the old format or the new format (for both requests and replies). For kernel->user multicasts, both types will be sent. setsockopt() will deduce the format from the length. Signed-off-by: Kevin Cernekee --- include/uapi/linux/xfrm.h | 152 ++- net/xfrm/xfrm_user.c| 136 --- net/xfrm/xfrm_user.h| 75 net/xfrm/xfrm_user_legacy.c | 169 security/selinux/nlmsgtab.c | 61 +--- 5 files changed, 466 insertions(+), 127 deletions(-) diff --git a/include/uapi/linux/xfrm.h b/include/uapi/linux/xfrm.h index 1fc62b239f1b..ae5f97681989 100644 --- a/include/uapi/linux/xfrm.h +++ b/include/uapi/linux/xfrm.h @@ -1,6 +1,7 @@ #ifndef _LINUX_XFRM_H #define _LINUX_XFRM_H +#include #include #include @@ -157,34 +158,34 @@ enum { enum { XFRM_MSG_BASE = 0x10, - XFRM_MSG_NEWSA = 0x10, -#define XFRM_MSG_NEWSA XFRM_MSG_NEWSA - XFRM_MSG_DELSA, -#define XFRM_MSG_DELSA XFRM_MSG_DELSA - XFRM_MSG_GETSA, -#define XFRM_MSG_GETSA XFRM_MSG_GETSA - - XFRM_MSG_NEWPOLICY, -#define XFRM_MSG_NEWPOLICY XFRM_MSG_NEWPOLICY - XFRM_MSG_DELPOLICY, -#define XFRM_MSG_DELPOLICY XFRM_MSG_DELPOLICY - XFRM_MSG_GETPOLICY, -#define XFRM_MSG_GETPOLICY XFRM_MSG_GETPOLICY - - XFRM_MSG_ALLOCSPI, -#define XFRM_MSG_ALLOCSPI XFRM_MSG_ALLOCSPI - XFRM_MSG_ACQUIRE, -#define XFRM_MSG_ACQUIRE XFRM_MSG_ACQUIRE - XFRM_MSG_EXPIRE, -#define XFRM_MSG_EXPIRE XFRM_MSG_EXPIRE - - XFRM_MSG_UPDPOLICY, -#define XFRM_MSG_UPDPOLICY XFRM_MSG_UPDPOLICY - XFRM_MSG_UPDSA, -#define XFRM_MSG_UPDSA XFRM_MSG_UPDSA - - XFRM_MSG_POLEXPIRE, -#define XFRM_MSG_POLEXPIRE XFRM_MSG_POLEXPIRE + XFRM_MSG_NEWSA_LEGACY = 0x10, +#define XFRM_MSG_NEWSA_LEGACY XFRM_MSG_NEWSA_LEGACY + XFRM_MSG_DELSA_LEGACY, +#define XFRM_MSG_DELSA_LEGACY XFRM_MSG_DELSA_LEGACY + XFRM_MSG_GETSA_LEGACY, +#define XFRM_MSG_GETSA_LEGACY XFRM_MSG_GETSA_LEGACY + + XFRM_MSG_NEWPOLICY_LEGACY, +#define XFRM_MSG_NEWPOLICY_LEGACY XFRM_MSG_NEWPOLICY_LEGACY + XFRM_MSG_DELPOLICY_LEGACY, +#define XFRM_MSG_DELPOLICY_LEGACY XFRM_MSG_DELPOLICY_LEGACY + XFRM_MSG_GETPOLICY_LEGACY, +#define XFRM_MSG_GETPOLICY_LEGACY XFRM_MSG_GETPOLICY_LEGACY + + XFRM_MSG_ALLOCSPI_LEGACY, +#define XFRM_MSG_ALLOCSPI_LEGACY XFRM_MSG_ALLOCSPI_LEGACY + XFRM_MSG_ACQUIRE_LEGACY, +#define XFRM_MSG_ACQUIRE_LEGACY XFRM_MSG_ACQUIRE_LEGACY + XFRM_MSG_EXPIRE_LEGACY, +#define XFRM_MSG_EXPIRE_LEGACY XFRM_MSG_EXPIRE_LEGACY + + XFRM_MSG_UPDPOLICY_LEGACY, +#define XFRM_MSG_UPDPOLICY_LEGACY XFRM_MSG_UPDPOLICY_LEGACY + XFRM_MSG_UPDSA_LEGACY, +#define XFRM_MSG_UPDSA_LEGACY XFRM_MSG_UPDSA_LEGACY + + XFRM_MSG_POLEXPIRE_LEGACY, +#define XFRM_MSG_POLEXPIRE_LEGACY XFRM_MSG_POLEXPIRE_LEGACY XFRM_MSG_FLUSHSA, #define XFRM_MSG_FLUSHSA XFRM_MSG_FLUSHSA @@ -214,6 +215,34 @@ enum { XFRM_MSG_MAPPING, #define XFRM_MSG_MAPPING XFRM_MSG_MAPPING + + XFRM_MSG_ALLOCSPI, +#define XFRM_MSG_ALLOCSPI XFRM_MSG_ALLOCSPI + XFRM_MSG_ACQUIRE, +#define XFRM_MSG_ACQUIRE XFRM_MSG_ACQUIRE + XFRM_MSG_EXPIRE, +#define XFRM_MSG_EXPIRE XFRM_MSG_EXPIRE + XFRM_MSG_POLEXPIRE, +#define XFRM_MSG_POLEXPIRE XFRM_MSG_POLEXPIRE + + XFRM_MSG_NEWSA, +#define XFRM_MSG_NEWSA XFRM_MSG_NEWSA + XFRM_MSG_UPDSA, +#define XFRM_MSG_UPDSA XFRM_MSG_UPDSA + XFRM_MSG_DELSA, +#define XFRM_MSG_DELSA XFRM_MSG_DELSA + XFRM_MSG_GETSA, +#define XFRM_MSG_GETSA XFRM_MSG_GETSA + + XFRM_MSG_NEWPOLICY, +#define XFRM_MSG_NEWPOLICY XFRM_MSG_NEWPOLICY + XFRM_MSG_UPDPOLICY, +#define XFRM_MSG_UPDPOLICY XFRM_MSG_UPDPOLICY + XFRM_MSG_DELPOLICY, +#define XFRM_MSG_DELPOLICY XFRM_MSG_DELPOLICY + XFRM_MSG_GETPOLICY, +#define XFRM_MSG_GETPOLICY XFRM_MSG_GETPOLICY + __XFRM_MSG_MAX }; #define XFRM_MSG_MAX (__XFRM_MSG_MAX - 1) @@ -221,7 +250,7 @@ enum { #define XFRM_NR_MSGTYPES (XFRM_MSG_MAX + 1 - XFRM_MSG_BASE) /* - * Generic LSM security context for comunicating to user space + * Generic LSM security context for communicating to user space * NOTE: Same format as sadb_x_sec_ctx */ struct xfrm_user_sec_ctx { @@ -357,6 +386,22 @@ struct xfrmu_spdhthresh { __u8 rbits; }; +/* Legacy structs are incompatible between 32-bit and 64-bit. */ +struct xfrm_usersa_info_legacy { + struct xfrm_selectorsel; + struct xfrm_id id; + xfrm_address_t saddr; + struct xfrm_lifetime_cfglft; + struct xfrm_lifetime_curcurlft; + struct xfrm
[PATCH 3/4] xfrm_user: Initial commit of xfrm_user_legacy.c
Several xfrm_* structs are incompatible between 32bit and 64bit builds: xfrm_usersa_info 220 bytes on i386 -> 224 bytes on amd64 xfrm_userpolicy_info 164 -> 168 xfrm_userspi_info 228 -> 232, offset mismatch on min xfrm_user_acquire 276 -> 280, offset mismatch on aalgos xfrm_user_expire 224 -> 232, offset mismatch on hard xfrm_user_polexpire 168 -> 176, offset mismatch on hard Fork all of the functions that handle these structs into a new file so that it is possible to support both legacy + new layouts. This commit contains an exact copy of the necessary functions from xfrm_user.c, for ease of reviewing. The next commit will contain all of the changes needed to make these functions handle legacy messages correctly. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- net/xfrm/Kconfig| 14 + net/xfrm/Makefile |8 +- net/xfrm/xfrm_user_legacy.c | 1091 +++ 3 files changed, 1112 insertions(+), 1 deletion(-) create mode 100644 net/xfrm/xfrm_user_legacy.c diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig index bda1a13628a8..317dcc411345 100644 --- a/net/xfrm/Kconfig +++ b/net/xfrm/Kconfig @@ -20,6 +20,20 @@ config XFRM_USER If unsure, say Y. +config XFRM_USER_LEGACY + tristate "Legacy transformation user configuration interface" + depends on XFRM_USER + default y + ---help--- + The original Transformation(XFRM) netlink messages were not + compatible between 32-bit programs and 64-bit kernels, so they + have been deprecated. Enable this option if you have existing + binaries that rely on the old format messages. Disable this + option if you know that all users of the interface have been + built against recent kernel headers. + + If unsure, say Y. + config XFRM_SUB_POLICY bool "Transformation sub policy support" depends on XFRM diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile index c0e961983f17..6cf6f8da3dc8 100644 --- a/net/xfrm/Makefile +++ b/net/xfrm/Makefile @@ -7,5 +7,11 @@ obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \ xfrm_sysctl.o xfrm_replay.o obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o -obj-$(CONFIG_XFRM_USER) += xfrm_user.o + +xfrm-user-objs := xfrm_user.o +ifneq ($(CONFIG_XFRM_USER_LEGACY),) +xfrm-user-objs += xfrm_user_legacy.o +endif +obj-$(CONFIG_XFRM_USER) += xfrm-user.o + obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o diff --git a/net/xfrm/xfrm_user_legacy.c b/net/xfrm/xfrm_user_legacy.c new file mode 100644 index ..058accfefc83 --- /dev/null +++ b/net/xfrm/xfrm_user_legacy.c @@ -0,0 +1,1091 @@ +/* xfrm_user.c: User interface to configure xfrm engine. + * + * Copyright (C) 2002 David S. Miller (da...@redhat.com) + * + * Changes: + * Mitsuru KANDA @USAGI + * Kazunori MIYAZAWA @USAGI + * Kunihiro Ishiguro <kunih...@ipinfusion.com> + * IPv6 support + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xfrm_user.h" + +static int xfrm_add_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + const struct xfrm_usersa_info *p = nlmsg_data(nlh); + struct xfrm_state *x; + int err; + struct km_event c; + + err = xfrm_verify_newsa_info(p, attrs); + if (err) + return err; + + x = xfrm_state_construct(net, p, attrs, ); + if (!x) + return err; + + xfrm_state_hold(x); + if (nlh->nlmsg_type == XFRM_MSG_NEWSA) + err = xfrm_state_add(x); + else + err = xfrm_state_update(x); + + xfrm_audit_state_add(x, err ? 0 : 1, true); + + if (err < 0) { + x->km.state = XFRM_STATE_DEAD; + __xfrm_state_put(x); + goto out; + } + + c.seq = nlh->nlmsg_seq; + c.portid = nlh->nlmsg_pid; + c.event = nlh->nlmsg_type; + + km_state_notify(x, ); +out: + xfrm_state_put(x); + return err; +} + +static int xfrm_del_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + struct xfrm_state *x; + int err = -ESRCH; + struct km_event c; + const struct xfrm_usersa_id *p = nlmsg_data(nlh); + + x = xfrm_user_state_lookup(net, p, attrs, ); + if (x == NULL) + return err; + + if ((err = security_xfrm_state_delete(x)) != 0) + goto out; + + if (xfrm_state_kern(x)) { + err = -EPERM; +
[PATCH 3/4] xfrm_user: Initial commit of xfrm_user_legacy.c
Several xfrm_* structs are incompatible between 32bit and 64bit builds: xfrm_usersa_info 220 bytes on i386 -> 224 bytes on amd64 xfrm_userpolicy_info 164 -> 168 xfrm_userspi_info 228 -> 232, offset mismatch on min xfrm_user_acquire 276 -> 280, offset mismatch on aalgos xfrm_user_expire 224 -> 232, offset mismatch on hard xfrm_user_polexpire 168 -> 176, offset mismatch on hard Fork all of the functions that handle these structs into a new file so that it is possible to support both legacy + new layouts. This commit contains an exact copy of the necessary functions from xfrm_user.c, for ease of reviewing. The next commit will contain all of the changes needed to make these functions handle legacy messages correctly. Signed-off-by: Kevin Cernekee --- net/xfrm/Kconfig| 14 + net/xfrm/Makefile |8 +- net/xfrm/xfrm_user_legacy.c | 1091 +++ 3 files changed, 1112 insertions(+), 1 deletion(-) create mode 100644 net/xfrm/xfrm_user_legacy.c diff --git a/net/xfrm/Kconfig b/net/xfrm/Kconfig index bda1a13628a8..317dcc411345 100644 --- a/net/xfrm/Kconfig +++ b/net/xfrm/Kconfig @@ -20,6 +20,20 @@ config XFRM_USER If unsure, say Y. +config XFRM_USER_LEGACY + tristate "Legacy transformation user configuration interface" + depends on XFRM_USER + default y + ---help--- + The original Transformation(XFRM) netlink messages were not + compatible between 32-bit programs and 64-bit kernels, so they + have been deprecated. Enable this option if you have existing + binaries that rely on the old format messages. Disable this + option if you know that all users of the interface have been + built against recent kernel headers. + + If unsure, say Y. + config XFRM_SUB_POLICY bool "Transformation sub policy support" depends on XFRM diff --git a/net/xfrm/Makefile b/net/xfrm/Makefile index c0e961983f17..6cf6f8da3dc8 100644 --- a/net/xfrm/Makefile +++ b/net/xfrm/Makefile @@ -7,5 +7,11 @@ obj-$(CONFIG_XFRM) := xfrm_policy.o xfrm_state.o xfrm_hash.o \ xfrm_sysctl.o xfrm_replay.o obj-$(CONFIG_XFRM_STATISTICS) += xfrm_proc.o obj-$(CONFIG_XFRM_ALGO) += xfrm_algo.o -obj-$(CONFIG_XFRM_USER) += xfrm_user.o + +xfrm-user-objs := xfrm_user.o +ifneq ($(CONFIG_XFRM_USER_LEGACY),) +xfrm-user-objs += xfrm_user_legacy.o +endif +obj-$(CONFIG_XFRM_USER) += xfrm-user.o + obj-$(CONFIG_XFRM_IPCOMP) += xfrm_ipcomp.o diff --git a/net/xfrm/xfrm_user_legacy.c b/net/xfrm/xfrm_user_legacy.c new file mode 100644 index ..058accfefc83 --- /dev/null +++ b/net/xfrm/xfrm_user_legacy.c @@ -0,0 +1,1091 @@ +/* xfrm_user.c: User interface to configure xfrm engine. + * + * Copyright (C) 2002 David S. Miller (da...@redhat.com) + * + * Changes: + * Mitsuru KANDA @USAGI + * Kazunori MIYAZAWA @USAGI + * Kunihiro Ishiguro + * IPv6 support + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include "xfrm_user.h" + +static int xfrm_add_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + const struct xfrm_usersa_info *p = nlmsg_data(nlh); + struct xfrm_state *x; + int err; + struct km_event c; + + err = xfrm_verify_newsa_info(p, attrs); + if (err) + return err; + + x = xfrm_state_construct(net, p, attrs, ); + if (!x) + return err; + + xfrm_state_hold(x); + if (nlh->nlmsg_type == XFRM_MSG_NEWSA) + err = xfrm_state_add(x); + else + err = xfrm_state_update(x); + + xfrm_audit_state_add(x, err ? 0 : 1, true); + + if (err < 0) { + x->km.state = XFRM_STATE_DEAD; + __xfrm_state_put(x); + goto out; + } + + c.seq = nlh->nlmsg_seq; + c.portid = nlh->nlmsg_pid; + c.event = nlh->nlmsg_type; + + km_state_notify(x, ); +out: + xfrm_state_put(x); + return err; +} + +static int xfrm_del_sa(struct sk_buff *skb, const struct nlmsghdr *nlh, + struct nlattr **attrs) +{ + struct net *net = sock_net(skb->sk); + struct xfrm_state *x; + int err = -ESRCH; + struct km_event c; + const struct xfrm_usersa_id *p = nlmsg_data(nlh); + + x = xfrm_user_state_lookup(net, p, attrs, ); + if (x == NULL) + return err; + + if ((err = security_xfrm_state_delete(x)) != 0) + goto out; + + if (xfrm_state_kern(x)) { + err = -EPERM; + goto out; + } + + err = xfrm_state_delete(x); + +
[RFC/PATCH 1/3] netfilter: ctnetlink: Fix regression in CTA_TIMEOUT processing
Commit b7bd1809e078 ("netfilter: nfnetlink_queue: get rid of nfnetlink_queue_ct.c") introduced a new check on the return value from the NFQA_CT parser (currently ctnetlink_glue_parse_ct()). Prior to Linux 4.4, nfqnl_ct_parse() would process the NFQA_EXP attribute even if there were errors in the NFQA_CT attribute. After Linux 4.4, this is no longer true, so any error in the NFQA_CT attribute will cause the kernel to silently fail to create an expectation. The new check is causing user conntrack helpers to fail. If a user program sends an NFQA_CT attribute containing a CTA_TIMEOUT attribute before the connection is confirmed (i.e. before the initial ACCEPT/DROP decision has been made), del_timer() in ctnetlink_change_timeout() will fail, and all further processing will be aborted. The (simplified) calling sequence looks like: nfnetlink_rcv_msg nfqnl_recv_verdict nfqnl_ct_parse ctnetlink_glue_parse_ct ctnetlink_change_timeout del_timer [ERROR] nf_reinject __nf_conntrack_confirm Fix this by adding a case to ctnetlink_change_timeout() to handle unconfirmed connections. Also, if a timeout of 0 is set for an unconfirmed connection, restore the old behavior of ignoring it (rather than setting up a connection that expires immediately). Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- net/netfilter/nf_conntrack_netlink.c | 12 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 9f5272968abb..43beb950df16 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1531,11 +1531,15 @@ ctnetlink_change_timeout(struct nf_conn *ct, const struct nlattr * const cda[]) { u_int32_t timeout = ntohl(nla_get_be32(cda[CTA_TIMEOUT])); - if (!del_timer(>timeout)) - return -ETIME; + if (nf_ct_is_confirmed(ct)) { + if (!del_timer(>timeout)) + return -ETIME; - ct->timeout.expires = jiffies + timeout * HZ; - add_timer(>timeout); + ct->timeout.expires = jiffies + timeout * HZ; + add_timer(>timeout); + } else if (timeout != 0) { + ct->timeout.expires = timeout * HZ; + } return 0; } -- 2.7.4
[RFC/PATCH 1/3] netfilter: ctnetlink: Fix regression in CTA_TIMEOUT processing
Commit b7bd1809e078 ("netfilter: nfnetlink_queue: get rid of nfnetlink_queue_ct.c") introduced a new check on the return value from the NFQA_CT parser (currently ctnetlink_glue_parse_ct()). Prior to Linux 4.4, nfqnl_ct_parse() would process the NFQA_EXP attribute even if there were errors in the NFQA_CT attribute. After Linux 4.4, this is no longer true, so any error in the NFQA_CT attribute will cause the kernel to silently fail to create an expectation. The new check is causing user conntrack helpers to fail. If a user program sends an NFQA_CT attribute containing a CTA_TIMEOUT attribute before the connection is confirmed (i.e. before the initial ACCEPT/DROP decision has been made), del_timer() in ctnetlink_change_timeout() will fail, and all further processing will be aborted. The (simplified) calling sequence looks like: nfnetlink_rcv_msg nfqnl_recv_verdict nfqnl_ct_parse ctnetlink_glue_parse_ct ctnetlink_change_timeout del_timer [ERROR] nf_reinject __nf_conntrack_confirm Fix this by adding a case to ctnetlink_change_timeout() to handle unconfirmed connections. Also, if a timeout of 0 is set for an unconfirmed connection, restore the old behavior of ignoring it (rather than setting up a connection that expires immediately). Signed-off-by: Kevin Cernekee --- net/netfilter/nf_conntrack_netlink.c | 12 1 file changed, 8 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 9f5272968abb..43beb950df16 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1531,11 +1531,15 @@ ctnetlink_change_timeout(struct nf_conn *ct, const struct nlattr * const cda[]) { u_int32_t timeout = ntohl(nla_get_be32(cda[CTA_TIMEOUT])); - if (!del_timer(>timeout)) - return -ETIME; + if (nf_ct_is_confirmed(ct)) { + if (!del_timer(>timeout)) + return -ETIME; - ct->timeout.expires = jiffies + timeout * HZ; - add_timer(>timeout); + ct->timeout.expires = jiffies + timeout * HZ; + add_timer(>timeout); + } else if (timeout != 0) { + ct->timeout.expires = timeout * HZ; + } return 0; } -- 2.7.4
[RFC/PATCH 2/3] netfilter: ctnetlink: Fix regression in CTA_STATUS processing
The libnetfilter_conntrack userland library always sets IPS_CONFIRMED when building a CTA_STATUS attribute. If this toggles the bit from 0->1, Linux 4.4+ will reject it and this will cause any NFQA_EXP attribute in the packet to be ignored. This breaks conntrackd's userland helpers because they operate on unconfirmed connections. Instead of returning -EBUSY if the user program asks to modify an unchangeable bit, simply ignore the change. Also, fix the logic so that user programs are allowed to clear the bits that they are allowed to change. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- include/uapi/linux/netfilter/nf_conntrack_common.h | 4 net/netfilter/nf_conntrack_netlink.c | 10 -- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h index 319f47128db8..846722d8e2a4 100644 --- a/include/uapi/linux/netfilter/nf_conntrack_common.h +++ b/include/uapi/linux/netfilter/nf_conntrack_common.h @@ -76,6 +76,10 @@ enum ip_conntrack_status { IPS_DYING_BIT = 9, IPS_DYING = (1 << IPS_DYING_BIT), + /* Bits that cannot be altered from userland. */ + IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK | +IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING), + /* Connection has fixed timeout. */ IPS_FIXED_TIMEOUT_BIT = 10, IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 43beb950df16..cc59f388928e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1422,10 +1422,6 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[]) unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS])); d = ct->status ^ status; - if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) - /* unchangeable */ - return -EBUSY; - if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) /* SEEN_REPLY bit can only be set */ return -EBUSY; @@ -1436,8 +1432,10 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[]) /* Be careful here, modifying NAT bits can screw up things, * so don't let users modify them directly if they don't pass -* nf_nat_range. */ - ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); +* nf_nat_range. Also, disallow changing bits that indicate +* which hash table owns the connection. */ + ct->status = (status & ~IPS_UNCHANGEABLE_MASK) | +(ct->status & IPS_UNCHANGEABLE_MASK); return 0; } -- 2.7.4
[RFC/PATCH 3/3] netfilter: ctnetlink: Fix regression in CTA_HELP processing
If a user program specifies CTA_HELP but the argument matches the current conntrack helper name, ignore it instead of generating an error. Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- net/netfilter/nf_conntrack_netlink.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index cc59f388928e..2912f582da65 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1472,14 +1472,19 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[]) struct nlattr *helpinfo = NULL; int err; - /* don't change helper of sibling connections */ - if (ct->master) - return -EBUSY; - err = ctnetlink_parse_help(cda[CTA_HELP], , ); if (err < 0) return err; + /* don't change helper of sibling connections */ + if (ct->master) { + if (help && help->helper && + !strcmp(help->helper->name, helpname)) + return 0; + else + return -EBUSY; + } + if (!strcmp(helpname, "")) { if (help && help->helper) { /* we had a helper before ... */ -- 2.7.4
[RFC/PATCH 2/3] netfilter: ctnetlink: Fix regression in CTA_STATUS processing
The libnetfilter_conntrack userland library always sets IPS_CONFIRMED when building a CTA_STATUS attribute. If this toggles the bit from 0->1, Linux 4.4+ will reject it and this will cause any NFQA_EXP attribute in the packet to be ignored. This breaks conntrackd's userland helpers because they operate on unconfirmed connections. Instead of returning -EBUSY if the user program asks to modify an unchangeable bit, simply ignore the change. Also, fix the logic so that user programs are allowed to clear the bits that they are allowed to change. Signed-off-by: Kevin Cernekee --- include/uapi/linux/netfilter/nf_conntrack_common.h | 4 net/netfilter/nf_conntrack_netlink.c | 10 -- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/include/uapi/linux/netfilter/nf_conntrack_common.h b/include/uapi/linux/netfilter/nf_conntrack_common.h index 319f47128db8..846722d8e2a4 100644 --- a/include/uapi/linux/netfilter/nf_conntrack_common.h +++ b/include/uapi/linux/netfilter/nf_conntrack_common.h @@ -76,6 +76,10 @@ enum ip_conntrack_status { IPS_DYING_BIT = 9, IPS_DYING = (1 << IPS_DYING_BIT), + /* Bits that cannot be altered from userland. */ + IPS_UNCHANGEABLE_MASK = (IPS_NAT_DONE_MASK | IPS_NAT_MASK | +IPS_EXPECTED | IPS_CONFIRMED | IPS_DYING), + /* Connection has fixed timeout. */ IPS_FIXED_TIMEOUT_BIT = 10, IPS_FIXED_TIMEOUT = (1 << IPS_FIXED_TIMEOUT_BIT), diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index 43beb950df16..cc59f388928e 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1422,10 +1422,6 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[]) unsigned int status = ntohl(nla_get_be32(cda[CTA_STATUS])); d = ct->status ^ status; - if (d & (IPS_EXPECTED|IPS_CONFIRMED|IPS_DYING)) - /* unchangeable */ - return -EBUSY; - if (d & IPS_SEEN_REPLY && !(status & IPS_SEEN_REPLY)) /* SEEN_REPLY bit can only be set */ return -EBUSY; @@ -1436,8 +1432,10 @@ ctnetlink_change_status(struct nf_conn *ct, const struct nlattr * const cda[]) /* Be careful here, modifying NAT bits can screw up things, * so don't let users modify them directly if they don't pass -* nf_nat_range. */ - ct->status |= status & ~(IPS_NAT_DONE_MASK | IPS_NAT_MASK); +* nf_nat_range. Also, disallow changing bits that indicate +* which hash table owns the connection. */ + ct->status = (status & ~IPS_UNCHANGEABLE_MASK) | +(ct->status & IPS_UNCHANGEABLE_MASK); return 0; } -- 2.7.4
[RFC/PATCH 3/3] netfilter: ctnetlink: Fix regression in CTA_HELP processing
If a user program specifies CTA_HELP but the argument matches the current conntrack helper name, ignore it instead of generating an error. Signed-off-by: Kevin Cernekee --- net/netfilter/nf_conntrack_netlink.c | 13 + 1 file changed, 9 insertions(+), 4 deletions(-) diff --git a/net/netfilter/nf_conntrack_netlink.c b/net/netfilter/nf_conntrack_netlink.c index cc59f388928e..2912f582da65 100644 --- a/net/netfilter/nf_conntrack_netlink.c +++ b/net/netfilter/nf_conntrack_netlink.c @@ -1472,14 +1472,19 @@ ctnetlink_change_helper(struct nf_conn *ct, const struct nlattr * const cda[]) struct nlattr *helpinfo = NULL; int err; - /* don't change helper of sibling connections */ - if (ct->master) - return -EBUSY; - err = ctnetlink_parse_help(cda[CTA_HELP], , ); if (err < 0) return err; + /* don't change helper of sibling connections */ + if (ct->master) { + if (help && help->helper && + !strcmp(help->helper->name, helpname)) + return 0; + else + return -EBUSY; + } + if (!strcmp(helpname, "")) { if (help && help->helper) { /* we had a helper before ... */ -- 2.7.4
[RFC/PATCH 0/3] Fix ctnetlink regressions
These patches address a problem I am seeing on Linux 4.4. They do not apply as-is to the master branch. But I wanted to run them past the list first to gather feedback on whether this is a reasonable approach. I am using the user conntrack helpers from conntrackd on systems running Linux 3.14, 3.18, and 4.4. It was observed that conntrackd worked fine on the 3.14/3.18 systems, but had no apparent effect on the 4.4 systems. I tracked this down to a new check that was added in 4.4: + if (nfq_ct->parse(nfqa[NFQA_CT], ct) < 0) + return NULL; + + if (nfqa[NFQA_EXP]) + nfq_ct->attach_expect(nfqa[NFQA_EXP], ct, + NETLINK_CB(entry->skb).portid, + nlmsg_report(nlh)); Prior to 4.4, even if a netlink message failed the parse() checks, the kernel would still run attach_expect() on it. This masked a number of failures. With 4.4+, a sanity check failure on any attribute checked by parse() will prevent the expectation from being created, which usually breaks the conntrack helper. In my testing I found that the sanity checks for CTA_TIMEOUT, CTA_STATUS, and CTA_HELP were overly strict. CTA_TIMEOUT may have been inadvertently fixed in master (commit f330a7fdbe161), but I don't think the other two are. My proposal is to relax the checks so that existing user programs do not break. Another option is to simply ignore the parse() result, so that the interface remains bug-compatible with old user code. Kevin Cernekee (3): netfilter: ctnetlink: Fix regression in CTA_TIMEOUT processing netfilter: ctnetlink: Fix regression in CTA_STATUS processing netfilter: ctnetlink: Fix regression in CTA_HELP processing include/uapi/linux/netfilter/nf_conntrack_common.h | 4 +++ net/netfilter/nf_conntrack_netlink.c | 35 +- 2 files changed, 25 insertions(+), 14 deletions(-) -- 2.7.4
[RFC/PATCH 0/3] Fix ctnetlink regressions
These patches address a problem I am seeing on Linux 4.4. They do not apply as-is to the master branch. But I wanted to run them past the list first to gather feedback on whether this is a reasonable approach. I am using the user conntrack helpers from conntrackd on systems running Linux 3.14, 3.18, and 4.4. It was observed that conntrackd worked fine on the 3.14/3.18 systems, but had no apparent effect on the 4.4 systems. I tracked this down to a new check that was added in 4.4: + if (nfq_ct->parse(nfqa[NFQA_CT], ct) < 0) + return NULL; + + if (nfqa[NFQA_EXP]) + nfq_ct->attach_expect(nfqa[NFQA_EXP], ct, + NETLINK_CB(entry->skb).portid, + nlmsg_report(nlh)); Prior to 4.4, even if a netlink message failed the parse() checks, the kernel would still run attach_expect() on it. This masked a number of failures. With 4.4+, a sanity check failure on any attribute checked by parse() will prevent the expectation from being created, which usually breaks the conntrack helper. In my testing I found that the sanity checks for CTA_TIMEOUT, CTA_STATUS, and CTA_HELP were overly strict. CTA_TIMEOUT may have been inadvertently fixed in master (commit f330a7fdbe161), but I don't think the other two are. My proposal is to relax the checks so that existing user programs do not break. Another option is to simply ignore the parse() result, so that the interface remains bug-compatible with old user code. Kevin Cernekee (3): netfilter: ctnetlink: Fix regression in CTA_TIMEOUT processing netfilter: ctnetlink: Fix regression in CTA_STATUS processing netfilter: ctnetlink: Fix regression in CTA_HELP processing include/uapi/linux/netfilter/nf_conntrack_common.h | 4 +++ net/netfilter/nf_conntrack_netlink.c | 35 +- 2 files changed, 25 insertions(+), 14 deletions(-) -- 2.7.4
[PATCH] printk: Make %pS print offsets into modules
If kallsyms cannot find a symbol for an address, entries like this will appear in backtraces: Call trace: [] 0xffbffc1ecd7c [] 0xffbffc1ef7f0 [] 0xffbffc1f0094 This isn't particularly useful for debugging because modules are not loaded at fixed addresses. Instead, print the offset from the module's base, so that the offending location can be easily located in a disassembly of the .ko file: Call trace: [] [mwifiex_pcie+0x37f4/0x9000] [] [mwifiex_pcie+0x40ac/0x9000] [] mwifiex_main_process+0xdc/0x6fc [mwifiex] Signed-off-by: Kevin Cernekee <cerne...@chromium.org> --- include/linux/module.h | 16 kernel/kallsyms.c | 19 ++- kernel/module.c| 23 +++ 3 files changed, 57 insertions(+), 1 deletion(-) Tested on 4.4 only (so the core_layout / init_layout stuff is untested). diff --git a/include/linux/module.h b/include/linux/module.h index 0c3207d26ac0..611d1e71b7c8 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -616,6 +616,14 @@ const char *module_address_lookup(unsigned long addr, unsigned long *offset, char **modname, char *namebuf); + +/* For kallsyms to ask which module, if any, contains addr. On success, + * returns true and populates module_size, module_offset, and modname. */ +bool module_base_lookup(unsigned long addr, + unsigned long *module_size, + unsigned long *module_offset, + char **modname); + int lookup_module_symbol_name(unsigned long addr, char *symname); int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name); @@ -698,6 +706,14 @@ static inline const char *module_address_lookup(unsigned long addr, return NULL; } +static inline bool module_base_lookup(unsigned long addr, + unsigned long *module_size, + unsigned long *module_offset, + char **modname) +{ + return false; +} + static inline int lookup_module_symbol_name(unsigned long addr, char *symname) { return -ERANGE; diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index fafd1a3ef0da..43b114e6861f 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -387,8 +387,25 @@ static int __sprint_symbol(char *buffer, unsigned long address, address += symbol_offset; name = kallsyms_lookup(address, , , , buffer); - if (!name) + if (!name) { + /* +* Fall back to [module_base+offset/size] if the actual +* symbol name is unavailable. +*/ + if (module_base_lookup(address, , , )) { + if (add_offset) { + return snprintf(buffer, KSYM_SYMBOL_LEN, + "[%s+%#lx/%#lx]", modname, + address - offset - + symbol_offset, + size); + } else { + return snprintf(buffer, KSYM_SYMBOL_LEN, + "[%s]", modname); + } + } return sprintf(buffer, "0x%lx", address - symbol_offset); + } if (name != buffer) strcpy(buffer, name); diff --git a/kernel/module.c b/kernel/module.c index f57dd63186e6..5e09f568c601 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3899,6 +3899,29 @@ const char *module_address_lookup(unsigned long addr, return ret; } +bool module_base_lookup(unsigned long addr, + unsigned long *module_size, + unsigned long *module_offset, + char **modname) +{ + struct module *mod; + + preempt_disable(); + + mod = __module_address(addr); + if (!mod) { + preempt_enable(); + return false; + } + + *modname = mod->name; + *module_offset = (unsigned long)mod->core_layout.base; + *module_size = mod->init_layout.size + mod->core_layout.size; + + preempt_enable(); + return true; +} + int lookup_module_symbol_name(unsigned long addr, char *symname) { struct module *mod; -- 2.8.0.rc3.226.g39d4020
[PATCH] printk: Make %pS print offsets into modules
If kallsyms cannot find a symbol for an address, entries like this will appear in backtraces: Call trace: [] 0xffbffc1ecd7c [] 0xffbffc1ef7f0 [] 0xffbffc1f0094 This isn't particularly useful for debugging because modules are not loaded at fixed addresses. Instead, print the offset from the module's base, so that the offending location can be easily located in a disassembly of the .ko file: Call trace: [] [mwifiex_pcie+0x37f4/0x9000] [] [mwifiex_pcie+0x40ac/0x9000] [] mwifiex_main_process+0xdc/0x6fc [mwifiex] Signed-off-by: Kevin Cernekee --- include/linux/module.h | 16 kernel/kallsyms.c | 19 ++- kernel/module.c| 23 +++ 3 files changed, 57 insertions(+), 1 deletion(-) Tested on 4.4 only (so the core_layout / init_layout stuff is untested). diff --git a/include/linux/module.h b/include/linux/module.h index 0c3207d26ac0..611d1e71b7c8 100644 --- a/include/linux/module.h +++ b/include/linux/module.h @@ -616,6 +616,14 @@ const char *module_address_lookup(unsigned long addr, unsigned long *offset, char **modname, char *namebuf); + +/* For kallsyms to ask which module, if any, contains addr. On success, + * returns true and populates module_size, module_offset, and modname. */ +bool module_base_lookup(unsigned long addr, + unsigned long *module_size, + unsigned long *module_offset, + char **modname); + int lookup_module_symbol_name(unsigned long addr, char *symname); int lookup_module_symbol_attrs(unsigned long addr, unsigned long *size, unsigned long *offset, char *modname, char *name); @@ -698,6 +706,14 @@ static inline const char *module_address_lookup(unsigned long addr, return NULL; } +static inline bool module_base_lookup(unsigned long addr, + unsigned long *module_size, + unsigned long *module_offset, + char **modname) +{ + return false; +} + static inline int lookup_module_symbol_name(unsigned long addr, char *symname) { return -ERANGE; diff --git a/kernel/kallsyms.c b/kernel/kallsyms.c index fafd1a3ef0da..43b114e6861f 100644 --- a/kernel/kallsyms.c +++ b/kernel/kallsyms.c @@ -387,8 +387,25 @@ static int __sprint_symbol(char *buffer, unsigned long address, address += symbol_offset; name = kallsyms_lookup(address, , , , buffer); - if (!name) + if (!name) { + /* +* Fall back to [module_base+offset/size] if the actual +* symbol name is unavailable. +*/ + if (module_base_lookup(address, , , )) { + if (add_offset) { + return snprintf(buffer, KSYM_SYMBOL_LEN, + "[%s+%#lx/%#lx]", modname, + address - offset - + symbol_offset, + size); + } else { + return snprintf(buffer, KSYM_SYMBOL_LEN, + "[%s]", modname); + } + } return sprintf(buffer, "0x%lx", address - symbol_offset); + } if (name != buffer) strcpy(buffer, name); diff --git a/kernel/module.c b/kernel/module.c index f57dd63186e6..5e09f568c601 100644 --- a/kernel/module.c +++ b/kernel/module.c @@ -3899,6 +3899,29 @@ const char *module_address_lookup(unsigned long addr, return ret; } +bool module_base_lookup(unsigned long addr, + unsigned long *module_size, + unsigned long *module_offset, + char **modname) +{ + struct module *mod; + + preempt_disable(); + + mod = __module_address(addr); + if (!mod) { + preempt_enable(); + return false; + } + + *modname = mod->name; + *module_offset = (unsigned long)mod->core_layout.base; + *module_size = mod->init_layout.size + mod->core_layout.size; + + preempt_enable(); + return true; +} + int lookup_module_symbol_name(unsigned long addr, char *symname) { struct module *mod; -- 2.8.0.rc3.226.g39d4020
Re: [PATCH] MIPS: Flush cache after DMA_FROM_DEVICE for agressively speculative CPUs
On Wed, May 13, 2015 at 6:49 PM, Leonid Yegoshin wrote: > Some MIPS CPUs have an aggressive speculative load and may erroneuosly load > some cache line in the middle of DMA transaction. CPU discards result but > cache > doesn't. If DMA happens from device then additional cache invalidation is > needed > on that CPU's after DMA. > > Found in test. > > Signed-off-by: Leonid Yegoshin > --- > arch/mips/mm/dma-default.c | 10 ++ > 1 file changed, 6 insertions(+), 4 deletions(-) > > diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c > index 609d1241b0c4..ccf49ecfbf8c 100644 > --- a/arch/mips/mm/dma-default.c > +++ b/arch/mips/mm/dma-default.c > @@ -67,11 +67,13 @@ static inline struct page *dma_addr_to_page(struct device > *dev, > * systems and only the R1 and R12000 are used in such systems, the > * SGI IP28 Indigo² rsp. SGI IP32 aka O2. > */ > -static inline int cpu_needs_post_dma_flush(struct device *dev) > +static inline int cpu_needs_post_dma_flush(struct device *dev, > + enum dma_data_direction direction) > { > return !plat_device_is_coherent(dev) && >(boot_cpu_type() == CPU_R1 || > boot_cpu_type() == CPU_R12000 || > + (cpu_has_maar && (direction != DMA_TO_DEVICE)) || > boot_cpu_type() == CPU_BMIPS5000); Can all of these CPUs safely skip the post_dma_flush on DMA_TO_DEVICE (not just maar)? -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH] MIPS: Flush cache after DMA_FROM_DEVICE for agressively speculative CPUs
On Wed, May 13, 2015 at 6:49 PM, Leonid Yegoshin leonid.yegos...@imgtec.com wrote: Some MIPS CPUs have an aggressive speculative load and may erroneuosly load some cache line in the middle of DMA transaction. CPU discards result but cache doesn't. If DMA happens from device then additional cache invalidation is needed on that CPU's after DMA. Found in test. Signed-off-by: Leonid Yegoshin leonid.yegos...@imgtec.com --- arch/mips/mm/dma-default.c | 10 ++ 1 file changed, 6 insertions(+), 4 deletions(-) diff --git a/arch/mips/mm/dma-default.c b/arch/mips/mm/dma-default.c index 609d1241b0c4..ccf49ecfbf8c 100644 --- a/arch/mips/mm/dma-default.c +++ b/arch/mips/mm/dma-default.c @@ -67,11 +67,13 @@ static inline struct page *dma_addr_to_page(struct device *dev, * systems and only the R1 and R12000 are used in such systems, the * SGI IP28 Indigo² rsp. SGI IP32 aka O2. */ -static inline int cpu_needs_post_dma_flush(struct device *dev) +static inline int cpu_needs_post_dma_flush(struct device *dev, + enum dma_data_direction direction) { return !plat_device_is_coherent(dev) (boot_cpu_type() == CPU_R1 || boot_cpu_type() == CPU_R12000 || + (cpu_has_maar (direction != DMA_TO_DEVICE)) || boot_cpu_type() == CPU_BMIPS5000); Can all of these CPUs safely skip the post_dma_flush on DMA_TO_DEVICE (not just maar)? -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V4 3/5] ASoC: tas571x: Add DT binding document
On Tue, May 5, 2015 at 3:32 PM, Mark Brown wrote: > On Tue, May 05, 2015 at 03:14:15PM -0700, Kevin Cernekee wrote: >> Document the bindings for the soon-to-be-added tas571x driver. > > If this is different to the already applied patches send incremental > updates. If this is the same as the version of the driver that is > already applied please don't resend already applied patches. OK - I sent an incremental update for the one thing that changed in the tas571x driver from V3 to V4. Note that the regcache changes were intentionally ordered before the tas571x commits, because the regcache changes are needed for the new driver to work correctly. In the for-next branch I see the tas571x commits, but not the regcache changes. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] ASoC: tas571x: Eliminate redundant dev->of_node NULL check
of_match_device() checks if dev->of_node is NULL, so we don't need to do it again in the probe function. Signed-off-by: Kevin Cernekee --- This applies to the broonie/sound.git for-next branch. sound/soc/codecs/tas571x.c | 13 - 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index b187ea53a7f9..85bcc374c8e8 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -377,6 +377,7 @@ static int tas571x_i2c_probe(struct i2c_client *client, { struct tas571x_private *priv; struct device *dev = >dev; + const struct of_device_id *of_id; int i, ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -384,18 +385,12 @@ static int tas571x_i2c_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, priv); - if (dev->of_node) { - const struct of_device_id *of_id; - - of_id = of_match_device(tas571x_of_match, dev); - if (of_id) - priv->chip = of_id->data; - } - - if (!priv->chip) { + of_id = of_match_device(tas571x_of_match, dev); + if (!of_id) { dev_err(dev, "Unknown device type\n"); return -EINVAL; } + priv->chip = of_id->data; priv->mclk = devm_clk_get(dev, "mclk"); if (IS_ERR(priv->mclk) && PTR_ERR(priv->mclk) != -ENOENT) { -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 3/5] ASoC: tas571x: Add DT binding document
Document the bindings for the soon-to-be-added tas571x driver. Signed-off-by: Kevin Cernekee --- .../devicetree/bindings/sound/tas571x.txt | 41 ++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt new file mode 100644 index ..0ac31d8d5ac4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tas571x.txt @@ -0,0 +1,41 @@ +Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers + +The codec is controlled through an I2C interface. It also has two other +signals that can be wired up to GPIOs: reset (strongly recommended), and +powerdown (optional). + +Required properties: + +- compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719" +- reg: The I2C address of the device +- #sound-dai-cells: must be equal to 0 + +Optional properties: + +- reset-gpios: GPIO specifier for the TAS571x's active low reset line +- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line +- clocks: clock phandle for the MCLK input +- clock-names: should be "mclk" +- AVDD-supply: regulator phandle for the AVDD supply (all chips) +- DVDD-supply: regulator phandle for the DVDD supply (all chips) +- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719) +- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719) +- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719) +- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711) +- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711) +- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711) +- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711) + +Example: + + tas5717: audio-codec@2a { + compatible = "ti,tas5717"; + reg = <0x2a>; + #sound-dai-cells = <0>; + + reset-gpios = < 1 GPIO_ACTIVE_LOW>; + pdn-gpios = < 2 GPIO_ACTIVE_LOW>; + + clocks = <_core CLK_I2S>; + clock-names = "mclk"; + }; -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 2/5] regmap: Use regcache_mark_dirty() to indicate power loss or reset
Existing regmap users call regcache_mark_dirty() as part of the suspend/resume sequence, to tell regcache that non-default values need to be resynced post-resume. Add an internal "no_sync_defaults" regmap flag to remember this state, so that regcache_sync() can differentiate between these two cases: 1) HW was reset, so any cache values that match map->reg_defaults can be safely skipped. On some chips there are a lot of registers in the reg_defaults list, so this optimization speeds things up quite a bit. 2) HW was not reset (maybe it was just clock-gated), so if we cached any writes, they should be sent to the hardware regardless of whether they match the HW default. Currently this will write out all values in the regcache, since we don't maintain per-register dirty bits. Suggested-by: Mark Brown Signed-off-by: Kevin Cernekee --- drivers/base/regmap/internal.h | 3 +++ drivers/base/regmap/regcache.c | 19 +++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index a13587b5c2be..b2b2849fc6d3 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -131,7 +131,10 @@ struct regmap { struct reg_default *reg_defaults; const void *reg_defaults_raw; void *cache; + /* if set, the cache contains newer data than the HW */ u32 cache_dirty; + /* if set, the HW registers are known to match map->reg_defaults */ + bool no_sync_defaults; struct reg_default *patch; int patch_regs; diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index c58493eaf050..b9862d741a56 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -254,6 +254,10 @@ static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg, { int ret; + /* If we don't know the chip just got reset, then sync everything. */ + if (!map->no_sync_defaults) + return true; + /* Is this the hardware default? If so skip. */ ret = regcache_lookup_reg(map, reg); if (ret >= 0 && val == map->reg_defaults[ret].def) @@ -352,6 +356,7 @@ out: /* Restore the bypass state */ map->async = false; map->cache_bypass = bypass; + map->no_sync_defaults = false; map->unlock(map->lock_arg); regmap_async_complete(map); @@ -407,6 +412,7 @@ out: /* Restore the bypass state */ map->cache_bypass = bypass; map->async = false; + map->no_sync_defaults = false; map->unlock(map->lock_arg); regmap_async_complete(map); @@ -471,18 +477,23 @@ void regcache_cache_only(struct regmap *map, bool enable) EXPORT_SYMBOL_GPL(regcache_cache_only); /** - * regcache_mark_dirty: Mark the register cache as dirty + * regcache_mark_dirty: Indicate that HW registers were reset to default values * * @map: map to mark * - * Mark the register cache as dirty, for example due to the device - * having been powered down for suspend. If the cache is not marked - * as dirty then the cache sync will be suppressed. + * Inform regcache that the device has been powered down or reset, so that + * on resume, regcache_sync() knows to write out all non-default values + * stored in the cache. + * + * If this function is not called, regcache_sync() will assume that + * the hardware state still matches the cache state, modulo any writes that + * happened when cache_only was true. */ void regcache_mark_dirty(struct regmap *map) { map->lock(map->lock_arg); map->cache_dirty = true; + map->no_sync_defaults = true; map->unlock(map->lock_arg); } EXPORT_SYMBOL_GPL(regcache_mark_dirty); -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 1/5] regmap: Add a helper function for regcache sync test
We're going to add another "does this register need syncing?" check, so rather than repeating it in three places, we'll separate all of the relevant logic into a helper function. Signed-off-by: Kevin Cernekee --- drivers/base/regmap/regcache.c | 26 +++--- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 7eb7b3b98794..c58493eaf050 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -249,6 +249,18 @@ int regcache_write(struct regmap *map, return 0; } +static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg, + unsigned int val) +{ + int ret; + + /* Is this the hardware default? If so skip. */ + ret = regcache_lookup_reg(map, reg); + if (ret >= 0 && val == map->reg_defaults[ret].def) + return false; + return true; +} + static int regcache_default_sync(struct regmap *map, unsigned int min, unsigned int max) { @@ -266,9 +278,7 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, if (ret) return ret; - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, reg); - if (ret >= 0 && val == map->reg_defaults[ret].def) + if (!regcache_reg_needs_sync(map, reg, val)) continue; map->cache_bypass = 1; @@ -613,10 +623,7 @@ static int regcache_sync_block_single(struct regmap *map, void *block, continue; val = regcache_get_val(map, block, i); - - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret >= 0 && val == map->reg_defaults[ret].def) + if (!regcache_reg_needs_sync(map, regtmp, val)) continue; map->cache_bypass = 1; @@ -688,10 +695,7 @@ static int regcache_sync_block_raw(struct regmap *map, void *block, } val = regcache_get_val(map, block, i); - - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret >= 0 && val == map->reg_defaults[ret].def) { + if (!regcache_reg_needs_sync(map, regtmp, val)) { ret = regcache_sync_block_raw_flush(map, , base, regtmp); if (ret != 0) -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 4/5] ASoC: tas571x: New driver for TI TAS571x power amplifiers
Introduce a new codec driver for the Texas Instruments TAS5711/TAS5717/TAS5719 power amplifier chips. These chips are typically used to take an I2S digital audio input and drive 10-20W into a pair of speakers. Signed-off-by: Kevin Cernekee --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 515 + sound/soc/codecs/tas571x.h | 33 +++ 4 files changed, 555 insertions(+) create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 061c46587628..befff910d71a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TAS2552 if I2C select SND_SOC_TAS5086 if I2C + select SND_SOC_TAS571X if I2C select SND_SOC_TFA9879 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER @@ -611,6 +612,10 @@ config SND_SOC_TAS5086 tristate "Texas Instruments TAS5086 speaker amplifier" depends on I2C +config SND_SOC_TAS571X + tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers" + depends on I2C + config SND_SOC_TFA9879 tristate "NXP Semiconductors TFA9879 amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index abe2d7edf65c..3dcf5ac85e89 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -106,6 +106,7 @@ snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o snd-soc-tas5086-objs := tas5086.o +snd-soc-tas571x-objs := tas571x.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o @@ -288,6 +289,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o +obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c new file mode 100644 index ..e724cc463e78 --- /dev/null +++ b/sound/soc/codecs/tas571x.c @@ -0,0 +1,515 @@ +/* + * TAS571x amplifier audio driver + * + * Copyright (C) 2015 Google, Inc. + * Copyright (c) 2013 Daniel Mack + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tas571x.h" + +#define TAS571X_MAX_SUPPLIES 6 + +struct tas571x_chip { + const char *const *supply_names; + int num_supply_names; + const struct snd_kcontrol_new *controls; + int num_controls; + const struct regmap_config *regmap_config; + int vol_reg_size; +}; + +struct tas571x_private { + const struct tas571x_chip *chip; + struct regmap *regmap; + struct regulator_bulk_data supplies[TAS571X_MAX_SUPPLIES]; + struct clk *mclk; + unsigned intformat; + struct gpio_desc*reset_gpio; + struct gpio_desc*pdn_gpio; + struct snd_soc_codec_driver codec_driver; +}; + +static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) +{ + switch (reg) { + case TAS571X_MVOL_REG: + case TAS571X_CH1_VOL_REG: + case TAS571X_CH2_VOL_REG: + return priv->chip->vol_reg_size; + default: + return 1; + } +} + +static int tas571x_reg_write(void *context, unsigned int reg, +unsigned int value) +{ + struct i2c_client *client = context; + struct tas571x_private *priv = i2c_get_clientdata(client); + unsigned int i, size; + uint8_t buf[5]; + int ret; + + size = tas571x_register_size(priv, reg); + buf[0] = reg; + + for (i = size; i >= 1; --i) { + buf[i] = value; + value >>= 8; + } + + ret = i2c_master_send(client, buf, size + 1); + if (ret == size + 1) + return
[PATCH V4 5/5] MAINTAINERS: Add entry for tas571x ASoC codec driver
Add self as maintainer for the new driver. Signed-off-by: Kevin Cernekee --- MAINTAINERS | 6 ++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ea0001760035..15153fc37cc4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9878,6 +9878,12 @@ L: net...@vger.kernel.org S: Maintained F: drivers/net/ethernet/ti/netcp* +TI TAS571X FAMILY ASoC CODEC DRIVER +M: Kevin Cernekee +L: alsa-de...@alsa-project.org (moderated for non-subscribers) +S: Odd Fixes +F: sound/soc/codecs/tas571x* + TI TWL4030 SERIES SOC CODEC DRIVER M: Peter Ujfalusi L: alsa-de...@alsa-project.org (moderated for non-subscribers) -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 0/5] tas571x amplifier driver
V3->V4: Eliminate unnecessary dev->of_node NULL check. Move the "should I sync this register?" test into a common helper function. Clear map->no_sync_defaults at the end of the regcache_sync functions. Kevin Cernekee (5): regmap: Add a helper function for regcache sync test regmap: Use regcache_mark_dirty() to indicate power loss or reset ASoC: tas571x: Add DT binding document ASoC: tas571x: New driver for TI TAS571x power amplifiers MAINTAINERS: Add entry for tas571x ASoC codec driver .../devicetree/bindings/sound/tas571x.txt | 41 ++ MAINTAINERS| 6 + drivers/base/regmap/internal.h | 3 + drivers/base/regmap/regcache.c | 45 +- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 515 + sound/soc/codecs/tas571x.h | 33 ++ 8 files changed, 635 insertions(+), 15 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 3/6] MAINTAINERS: Remove section BROADCOM BCM33XX MIPS ARCHITECTURE
On Tue, May 5, 2015 at 9:32 AM, Joe Perches wrote: > commit 5f2d44591fb3 ("MIPS: bcm3384: Rename "bcm3384" target to "bmips"") > renamed the files and integrated them into an existing section. > > Remove the section. > > Signed-off-by: Joe Perches > cc: Kevin Cernekee > --- > MAINTAINERS | 8 > 1 file changed, 8 deletions(-) > > diff --git a/MAINTAINERS b/MAINTAINERS > index bbfb324..f2fd5c7 100644 > --- a/MAINTAINERS > +++ b/MAINTAINERS > @@ -2141,14 +2141,6 @@ T: git > git://git.kernel.org/pub/scm/linux/kernel/git/rpi/linux-rpi.git > S: Maintained > N: bcm2835 > > -BROADCOM BCM33XX MIPS ARCHITECTURE > -M: Kevin Cernekee > -L: linux-m...@linux-mips.org > -S: Maintained > -F: arch/mips/bcm3384/* > -F: arch/mips/include/asm/mach-bcm3384/* > -F: arch/mips/kernel/*bmips* > - > BROADCOM BCM5301X ARM ARCHITECTURE > M: Hauke Mehrtens > L: linux-arm-ker...@lists.infradead.org > -- > 2.1.4 > Acked-by: Kevin Cernekee -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V4 3/5] ASoC: tas571x: Add DT binding document
On Tue, May 5, 2015 at 3:32 PM, Mark Brown broo...@kernel.org wrote: On Tue, May 05, 2015 at 03:14:15PM -0700, Kevin Cernekee wrote: Document the bindings for the soon-to-be-added tas571x driver. If this is different to the already applied patches send incremental updates. If this is the same as the version of the driver that is already applied please don't resend already applied patches. OK - I sent an incremental update for the one thing that changed in the tas571x driver from V3 to V4. Note that the regcache changes were intentionally ordered before the tas571x commits, because the regcache changes are needed for the new driver to work correctly. In the for-next branch I see the tas571x commits, but not the regcache changes. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] ASoC: tas571x: Eliminate redundant dev-of_node NULL check
of_match_device() checks if dev-of_node is NULL, so we don't need to do it again in the probe function. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- This applies to the broonie/sound.git for-next branch. sound/soc/codecs/tas571x.c | 13 - 1 file changed, 4 insertions(+), 9 deletions(-) diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c index b187ea53a7f9..85bcc374c8e8 100644 --- a/sound/soc/codecs/tas571x.c +++ b/sound/soc/codecs/tas571x.c @@ -377,6 +377,7 @@ static int tas571x_i2c_probe(struct i2c_client *client, { struct tas571x_private *priv; struct device *dev = client-dev; + const struct of_device_id *of_id; int i, ret; priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL); @@ -384,18 +385,12 @@ static int tas571x_i2c_probe(struct i2c_client *client, return -ENOMEM; i2c_set_clientdata(client, priv); - if (dev-of_node) { - const struct of_device_id *of_id; - - of_id = of_match_device(tas571x_of_match, dev); - if (of_id) - priv-chip = of_id-data; - } - - if (!priv-chip) { + of_id = of_match_device(tas571x_of_match, dev); + if (!of_id) { dev_err(dev, Unknown device type\n); return -EINVAL; } + priv-chip = of_id-data; priv-mclk = devm_clk_get(dev, mclk); if (IS_ERR(priv-mclk) PTR_ERR(priv-mclk) != -ENOENT) { -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 4/5] ASoC: tas571x: New driver for TI TAS571x power amplifiers
Introduce a new codec driver for the Texas Instruments TAS5711/TAS5717/TAS5719 power amplifier chips. These chips are typically used to take an I2S digital audio input and drive 10-20W into a pair of speakers. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 515 + sound/soc/codecs/tas571x.h | 33 +++ 4 files changed, 555 insertions(+) create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 061c46587628..befff910d71a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TAS2552 if I2C select SND_SOC_TAS5086 if I2C + select SND_SOC_TAS571X if I2C select SND_SOC_TFA9879 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER @@ -611,6 +612,10 @@ config SND_SOC_TAS5086 tristate Texas Instruments TAS5086 speaker amplifier depends on I2C +config SND_SOC_TAS571X + tristate Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers + depends on I2C + config SND_SOC_TFA9879 tristate NXP Semiconductors TFA9879 amplifier depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index abe2d7edf65c..3dcf5ac85e89 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -106,6 +106,7 @@ snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o snd-soc-tas5086-objs := tas5086.o +snd-soc-tas571x-objs := tas571x.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o @@ -288,6 +289,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o +obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c new file mode 100644 index ..e724cc463e78 --- /dev/null +++ b/sound/soc/codecs/tas571x.c @@ -0,0 +1,515 @@ +/* + * TAS571x amplifier audio driver + * + * Copyright (C) 2015 Google, Inc. + * Copyright (c) 2013 Daniel Mack zon...@gmail.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include linux/clk.h +#include linux/delay.h +#include linux/device.h +#include linux/gpio/consumer.h +#include linux/i2c.h +#include linux/init.h +#include linux/kernel.h +#include linux/module.h +#include linux/of_device.h +#include linux/regmap.h +#include linux/regulator/consumer.h +#include linux/stddef.h +#include sound/pcm_params.h +#include sound/soc.h +#include sound/tlv.h + +#include tas571x.h + +#define TAS571X_MAX_SUPPLIES 6 + +struct tas571x_chip { + const char *const *supply_names; + int num_supply_names; + const struct snd_kcontrol_new *controls; + int num_controls; + const struct regmap_config *regmap_config; + int vol_reg_size; +}; + +struct tas571x_private { + const struct tas571x_chip *chip; + struct regmap *regmap; + struct regulator_bulk_data supplies[TAS571X_MAX_SUPPLIES]; + struct clk *mclk; + unsigned intformat; + struct gpio_desc*reset_gpio; + struct gpio_desc*pdn_gpio; + struct snd_soc_codec_driver codec_driver; +}; + +static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) +{ + switch (reg) { + case TAS571X_MVOL_REG: + case TAS571X_CH1_VOL_REG: + case TAS571X_CH2_VOL_REG: + return priv-chip-vol_reg_size; + default: + return 1; + } +} + +static int tas571x_reg_write(void *context, unsigned int reg, +unsigned int value) +{ + struct i2c_client *client = context; + struct tas571x_private *priv = i2c_get_clientdata(client); + unsigned int i, size; + uint8_t buf[5]; + int ret; + + size = tas571x_register_size(priv, reg); + buf[0] = reg; + + for (i = size; i = 1
[PATCH V4 0/5] tas571x amplifier driver
V3-V4: Eliminate unnecessary dev-of_node NULL check. Move the should I sync this register? test into a common helper function. Clear map-no_sync_defaults at the end of the regcache_sync functions. Kevin Cernekee (5): regmap: Add a helper function for regcache sync test regmap: Use regcache_mark_dirty() to indicate power loss or reset ASoC: tas571x: Add DT binding document ASoC: tas571x: New driver for TI TAS571x power amplifiers MAINTAINERS: Add entry for tas571x ASoC codec driver .../devicetree/bindings/sound/tas571x.txt | 41 ++ MAINTAINERS| 6 + drivers/base/regmap/internal.h | 3 + drivers/base/regmap/regcache.c | 45 +- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 515 + sound/soc/codecs/tas571x.h | 33 ++ 8 files changed, 635 insertions(+), 15 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 5/5] MAINTAINERS: Add entry for tas571x ASoC codec driver
Add self as maintainer for the new driver. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- MAINTAINERS | 6 ++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ea0001760035..15153fc37cc4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9878,6 +9878,12 @@ L: net...@vger.kernel.org S: Maintained F: drivers/net/ethernet/ti/netcp* +TI TAS571X FAMILY ASoC CODEC DRIVER +M: Kevin Cernekee cerne...@chromium.org +L: alsa-de...@alsa-project.org (moderated for non-subscribers) +S: Odd Fixes +F: sound/soc/codecs/tas571x* + TI TWL4030 SERIES SOC CODEC DRIVER M: Peter Ujfalusi peter.ujfal...@ti.com L: alsa-de...@alsa-project.org (moderated for non-subscribers) -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 1/5] regmap: Add a helper function for regcache sync test
We're going to add another does this register need syncing? check, so rather than repeating it in three places, we'll separate all of the relevant logic into a helper function. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- drivers/base/regmap/regcache.c | 26 +++--- 1 file changed, 15 insertions(+), 11 deletions(-) diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 7eb7b3b98794..c58493eaf050 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -249,6 +249,18 @@ int regcache_write(struct regmap *map, return 0; } +static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg, + unsigned int val) +{ + int ret; + + /* Is this the hardware default? If so skip. */ + ret = regcache_lookup_reg(map, reg); + if (ret = 0 val == map-reg_defaults[ret].def) + return false; + return true; +} + static int regcache_default_sync(struct regmap *map, unsigned int min, unsigned int max) { @@ -266,9 +278,7 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, if (ret) return ret; - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, reg); - if (ret = 0 val == map-reg_defaults[ret].def) + if (!regcache_reg_needs_sync(map, reg, val)) continue; map-cache_bypass = 1; @@ -613,10 +623,7 @@ static int regcache_sync_block_single(struct regmap *map, void *block, continue; val = regcache_get_val(map, block, i); - - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret = 0 val == map-reg_defaults[ret].def) + if (!regcache_reg_needs_sync(map, regtmp, val)) continue; map-cache_bypass = 1; @@ -688,10 +695,7 @@ static int regcache_sync_block_raw(struct regmap *map, void *block, } val = regcache_get_val(map, block, i); - - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret = 0 val == map-reg_defaults[ret].def) { + if (!regcache_reg_needs_sync(map, regtmp, val)) { ret = regcache_sync_block_raw_flush(map, data, base, regtmp); if (ret != 0) -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 3/5] ASoC: tas571x: Add DT binding document
Document the bindings for the soon-to-be-added tas571x driver. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- .../devicetree/bindings/sound/tas571x.txt | 41 ++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt new file mode 100644 index ..0ac31d8d5ac4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tas571x.txt @@ -0,0 +1,41 @@ +Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers + +The codec is controlled through an I2C interface. It also has two other +signals that can be wired up to GPIOs: reset (strongly recommended), and +powerdown (optional). + +Required properties: + +- compatible: ti,tas5711, ti,tas5717, or ti,tas5719 +- reg: The I2C address of the device +- #sound-dai-cells: must be equal to 0 + +Optional properties: + +- reset-gpios: GPIO specifier for the TAS571x's active low reset line +- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line +- clocks: clock phandle for the MCLK input +- clock-names: should be mclk +- AVDD-supply: regulator phandle for the AVDD supply (all chips) +- DVDD-supply: regulator phandle for the DVDD supply (all chips) +- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719) +- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719) +- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719) +- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711) +- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711) +- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711) +- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711) + +Example: + + tas5717: audio-codec@2a { + compatible = ti,tas5717; + reg = 0x2a; + #sound-dai-cells = 0; + + reset-gpios = gpio5 1 GPIO_ACTIVE_LOW; + pdn-gpios = gpio5 2 GPIO_ACTIVE_LOW; + + clocks = clk_core CLK_I2S; + clock-names = mclk; + }; -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V4 2/5] regmap: Use regcache_mark_dirty() to indicate power loss or reset
Existing regmap users call regcache_mark_dirty() as part of the suspend/resume sequence, to tell regcache that non-default values need to be resynced post-resume. Add an internal no_sync_defaults regmap flag to remember this state, so that regcache_sync() can differentiate between these two cases: 1) HW was reset, so any cache values that match map-reg_defaults can be safely skipped. On some chips there are a lot of registers in the reg_defaults list, so this optimization speeds things up quite a bit. 2) HW was not reset (maybe it was just clock-gated), so if we cached any writes, they should be sent to the hardware regardless of whether they match the HW default. Currently this will write out all values in the regcache, since we don't maintain per-register dirty bits. Suggested-by: Mark Brown broo...@kernel.org Signed-off-by: Kevin Cernekee cerne...@chromium.org --- drivers/base/regmap/internal.h | 3 +++ drivers/base/regmap/regcache.c | 19 +++ 2 files changed, 18 insertions(+), 4 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index a13587b5c2be..b2b2849fc6d3 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -131,7 +131,10 @@ struct regmap { struct reg_default *reg_defaults; const void *reg_defaults_raw; void *cache; + /* if set, the cache contains newer data than the HW */ u32 cache_dirty; + /* if set, the HW registers are known to match map-reg_defaults */ + bool no_sync_defaults; struct reg_default *patch; int patch_regs; diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index c58493eaf050..b9862d741a56 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -254,6 +254,10 @@ static bool regcache_reg_needs_sync(struct regmap *map, unsigned int reg, { int ret; + /* If we don't know the chip just got reset, then sync everything. */ + if (!map-no_sync_defaults) + return true; + /* Is this the hardware default? If so skip. */ ret = regcache_lookup_reg(map, reg); if (ret = 0 val == map-reg_defaults[ret].def) @@ -352,6 +356,7 @@ out: /* Restore the bypass state */ map-async = false; map-cache_bypass = bypass; + map-no_sync_defaults = false; map-unlock(map-lock_arg); regmap_async_complete(map); @@ -407,6 +412,7 @@ out: /* Restore the bypass state */ map-cache_bypass = bypass; map-async = false; + map-no_sync_defaults = false; map-unlock(map-lock_arg); regmap_async_complete(map); @@ -471,18 +477,23 @@ void regcache_cache_only(struct regmap *map, bool enable) EXPORT_SYMBOL_GPL(regcache_cache_only); /** - * regcache_mark_dirty: Mark the register cache as dirty + * regcache_mark_dirty: Indicate that HW registers were reset to default values * * @map: map to mark * - * Mark the register cache as dirty, for example due to the device - * having been powered down for suspend. If the cache is not marked - * as dirty then the cache sync will be suppressed. + * Inform regcache that the device has been powered down or reset, so that + * on resume, regcache_sync() knows to write out all non-default values + * stored in the cache. + * + * If this function is not called, regcache_sync() will assume that + * the hardware state still matches the cache state, modulo any writes that + * happened when cache_only was true. */ void regcache_mark_dirty(struct regmap *map) { map-lock(map-lock_arg); map-cache_dirty = true; + map-no_sync_defaults = true; map-unlock(map-lock_arg); } EXPORT_SYMBOL_GPL(regcache_mark_dirty); -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 3/6] MAINTAINERS: Remove section BROADCOM BCM33XX MIPS ARCHITECTURE
On Tue, May 5, 2015 at 9:32 AM, Joe Perches j...@perches.com wrote: commit 5f2d44591fb3 (MIPS: bcm3384: Rename bcm3384 target to bmips) renamed the files and integrated them into an existing section. Remove the section. Signed-off-by: Joe Perches j...@perches.com cc: Kevin Cernekee cerne...@gmail.com --- MAINTAINERS | 8 1 file changed, 8 deletions(-) diff --git a/MAINTAINERS b/MAINTAINERS index bbfb324..f2fd5c7 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -2141,14 +2141,6 @@ T: git git://git.kernel.org/pub/scm/linux/kernel/git/rpi/linux-rpi.git S: Maintained N: bcm2835 -BROADCOM BCM33XX MIPS ARCHITECTURE -M: Kevin Cernekee cerne...@gmail.com -L: linux-m...@linux-mips.org -S: Maintained -F: arch/mips/bcm3384/* -F: arch/mips/include/asm/mach-bcm3384/* -F: arch/mips/kernel/*bmips* - BROADCOM BCM5301X ARM ARCHITECTURE M: Hauke Mehrtens ha...@hauke-m.de L: linux-arm-ker...@lists.infradead.org -- 2.1.4 Acked-by: Kevin Cernekee cerne...@gmail.com -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V3 1/4] regmap: Use regcache_mark_dirty() to indicate power loss or reset
On Sun, May 3, 2015 at 11:38 PM, Lars-Peter Clausen wrote: >> diff --git a/drivers/base/regmap/regcache.c >> b/drivers/base/regmap/regcache.c >> index 7eb7b3b98794..63af3103d0c6 100644 >> --- a/drivers/base/regmap/regcache.c >> +++ b/drivers/base/regmap/regcache.c >> @@ -253,6 +253,9 @@ static int regcache_default_sync(struct regmap *map, >> unsigned int min, >> unsigned int max) >> { >> unsigned int reg; >> + bool no_sync_defaults = map->no_sync_defaults; >> + >> + map->no_sync_defaults = false; > > > This needs to be done at the end in regcache_sync(), the same place where > dirty is set to false. But map->cache_dirty means "any register is dirty," not "all registers are dirty." So it can only be cleared after a successful flush. If one of the writes fails and regcache_sync() has to return prematurely, we probably don't want no_sync_defaults to stay true because some of the HW registers might not match map->reg_defaults anymore. Leaving it set to true wouldn't break the current regcache_sync() implementation, but no_sync_defaults is documented as: "if set, the HW registers are known to match map->reg_defaults". Writing any register to a non-default value makes it false. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V3 3/4] ASoC: tas571x: New driver for TI TAS571x power amplifiers
On Mon, May 4, 2015 at 4:45 AM, Mark Brown wrote: > On Sun, May 03, 2015 at 05:00:18PM -0700, Kevin Cernekee wrote: >> + if (dev->of_node) { >> + const struct of_device_id *of_id; >> + >> + of_id = of_match_device(tas571x_of_match, dev); >> + if (of_id) >> + priv->chip = of_id->data; >> + } > > Doesn't of_match_device() do the right thing with devices not registered > from DT? Not sure. What kinds of situations are you concerned about? -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V3 3/4] ASoC: tas571x: New driver for TI TAS571x power amplifiers
On Mon, May 4, 2015 at 4:45 AM, Mark Brown broo...@kernel.org wrote: On Sun, May 03, 2015 at 05:00:18PM -0700, Kevin Cernekee wrote: + if (dev-of_node) { + const struct of_device_id *of_id; + + of_id = of_match_device(tas571x_of_match, dev); + if (of_id) + priv-chip = of_id-data; + } Doesn't of_match_device() do the right thing with devices not registered from DT? Not sure. What kinds of situations are you concerned about? -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V3 1/4] regmap: Use regcache_mark_dirty() to indicate power loss or reset
On Sun, May 3, 2015 at 11:38 PM, Lars-Peter Clausen l...@metafoo.de wrote: diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 7eb7b3b98794..63af3103d0c6 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -253,6 +253,9 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, unsigned int max) { unsigned int reg; + bool no_sync_defaults = map-no_sync_defaults; + + map-no_sync_defaults = false; This needs to be done at the end in regcache_sync(), the same place where dirty is set to false. But map-cache_dirty means any register is dirty, not all registers are dirty. So it can only be cleared after a successful flush. If one of the writes fails and regcache_sync() has to return prematurely, we probably don't want no_sync_defaults to stay true because some of the HW registers might not match map-reg_defaults anymore. Leaving it set to true wouldn't break the current regcache_sync() implementation, but no_sync_defaults is documented as: if set, the HW registers are known to match map-reg_defaults. Writing any register to a non-default value makes it false. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3 4/4] MAINTAINERS: Add entry for tas571x ASoC codec driver
Add self as maintainer for the new driver. Signed-off-by: Kevin Cernekee --- MAINTAINERS | 6 ++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ea0001760035..15153fc37cc4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9878,6 +9878,12 @@ L: net...@vger.kernel.org S: Maintained F: drivers/net/ethernet/ti/netcp* +TI TAS571X FAMILY ASoC CODEC DRIVER +M: Kevin Cernekee +L: alsa-de...@alsa-project.org (moderated for non-subscribers) +S: Odd Fixes +F: sound/soc/codecs/tas571x* + TI TWL4030 SERIES SOC CODEC DRIVER M: Peter Ujfalusi L: alsa-de...@alsa-project.org (moderated for non-subscribers) -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3 2/4] ASoC: tas571x: Add DT binding document
Document the bindings for the soon-to-be-added tas571x driver. Signed-off-by: Kevin Cernekee --- .../devicetree/bindings/sound/tas571x.txt | 41 ++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt new file mode 100644 index ..0ac31d8d5ac4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tas571x.txt @@ -0,0 +1,41 @@ +Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers + +The codec is controlled through an I2C interface. It also has two other +signals that can be wired up to GPIOs: reset (strongly recommended), and +powerdown (optional). + +Required properties: + +- compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719" +- reg: The I2C address of the device +- #sound-dai-cells: must be equal to 0 + +Optional properties: + +- reset-gpios: GPIO specifier for the TAS571x's active low reset line +- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line +- clocks: clock phandle for the MCLK input +- clock-names: should be "mclk" +- AVDD-supply: regulator phandle for the AVDD supply (all chips) +- DVDD-supply: regulator phandle for the DVDD supply (all chips) +- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719) +- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719) +- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719) +- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711) +- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711) +- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711) +- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711) + +Example: + + tas5717: audio-codec@2a { + compatible = "ti,tas5717"; + reg = <0x2a>; + #sound-dai-cells = <0>; + + reset-gpios = < 1 GPIO_ACTIVE_LOW>; + pdn-gpios = < 2 GPIO_ACTIVE_LOW>; + + clocks = <_core CLK_I2S>; + clock-names = "mclk"; + }; -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3 3/4] ASoC: tas571x: New driver for TI TAS571x power amplifiers
Introduce a new codec driver for the Texas Instruments TAS5711/TAS5717/TAS5719 power amplifier chips. These chips are typically used to take an I2S digital audio input and drive 10-20W into a pair of speakers. Signed-off-by: Kevin Cernekee --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 520 + sound/soc/codecs/tas571x.h | 33 +++ 4 files changed, 560 insertions(+) create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 061c46587628..befff910d71a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TAS2552 if I2C select SND_SOC_TAS5086 if I2C + select SND_SOC_TAS571X if I2C select SND_SOC_TFA9879 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER @@ -611,6 +612,10 @@ config SND_SOC_TAS5086 tristate "Texas Instruments TAS5086 speaker amplifier" depends on I2C +config SND_SOC_TAS571X + tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers" + depends on I2C + config SND_SOC_TFA9879 tristate "NXP Semiconductors TFA9879 amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index abe2d7edf65c..3dcf5ac85e89 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -106,6 +106,7 @@ snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o snd-soc-tas5086-objs := tas5086.o +snd-soc-tas571x-objs := tas571x.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o @@ -288,6 +289,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o +obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c new file mode 100644 index ..ffdf48397491 --- /dev/null +++ b/sound/soc/codecs/tas571x.c @@ -0,0 +1,520 @@ +/* + * TAS571x amplifier audio driver + * + * Copyright (C) 2015 Google, Inc. + * Copyright (c) 2013 Daniel Mack + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tas571x.h" + +#define TAS571X_MAX_SUPPLIES 6 + +struct tas571x_chip { + const char *const *supply_names; + int num_supply_names; + const struct snd_kcontrol_new *controls; + int num_controls; + const struct regmap_config *regmap_config; + int vol_reg_size; +}; + +struct tas571x_private { + const struct tas571x_chip *chip; + struct regmap *regmap; + struct regulator_bulk_data supplies[TAS571X_MAX_SUPPLIES]; + struct clk *mclk; + unsigned intformat; + struct gpio_desc*reset_gpio; + struct gpio_desc*pdn_gpio; + struct snd_soc_codec_driver codec_driver; +}; + +static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) +{ + switch (reg) { + case TAS571X_MVOL_REG: + case TAS571X_CH1_VOL_REG: + case TAS571X_CH2_VOL_REG: + return priv->chip->vol_reg_size; + default: + return 1; + } +} + +static int tas571x_reg_write(void *context, unsigned int reg, +unsigned int value) +{ + struct i2c_client *client = context; + struct tas571x_private *priv = i2c_get_clientdata(client); + unsigned int i, size; + uint8_t buf[5]; + int ret; + + size = tas571x_register_size(priv, reg); + buf[0] = reg; + + for (i = size; i >= 1; --i) { + buf[i] = value; + value >>= 8; + } + + ret = i2c_master_send(client, buf, size + 1); + if (ret == size + 1) + return
[PATCH V3 1/4] regmap: Use regcache_mark_dirty() to indicate power loss or reset
Existing regmap users call regcache_mark_dirty() as part of the suspend/resume sequence, to tell regcache that non-default values need to be resynced post-resume. Add an internal "no_sync_defaults" regmap flag to remember this state, so that regcache_sync() can differentiate between these two cases: 1) HW was reset, so any cache values that match map->reg_defaults can be safely skipped. On some chips there are a lot of registers in the reg_defaults list, so this optimization speeds things up quite a bit. 2) HW was not reset (maybe it was just clock-gated), so if we cached any writes, they should be sent to the hardware regardless of whether they match the HW default. Currently this will write out all values in the regcache, since we don't maintain per-register dirty bits. Suggested-by: Mark Brown Signed-off-by: Kevin Cernekee --- drivers/base/regmap/internal.h | 3 +++ drivers/base/regmap/regcache.c | 61 -- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index a13587b5c2be..b2b2849fc6d3 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -131,7 +131,10 @@ struct regmap { struct reg_default *reg_defaults; const void *reg_defaults_raw; void *cache; + /* if set, the cache contains newer data than the HW */ u32 cache_dirty; + /* if set, the HW registers are known to match map->reg_defaults */ + bool no_sync_defaults; struct reg_default *patch; int patch_regs; diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 7eb7b3b98794..63af3103d0c6 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -253,6 +253,9 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, unsigned int max) { unsigned int reg; + bool no_sync_defaults = map->no_sync_defaults; + + map->no_sync_defaults = false; for (reg = min; reg <= max; reg += map->reg_stride) { unsigned int val; @@ -266,10 +269,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, if (ret) return ret; - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, reg); - if (ret >= 0 && val == map->reg_defaults[ret].def) - continue; + if (no_sync_defaults) { + /* Is this the hardware default? If so skip. */ + ret = regcache_lookup_reg(map, reg); + if (ret >= 0 && val == map->reg_defaults[ret].def) + continue; + } map->cache_bypass = 1; ret = _regmap_write(map, reg, val); @@ -461,18 +466,23 @@ void regcache_cache_only(struct regmap *map, bool enable) EXPORT_SYMBOL_GPL(regcache_cache_only); /** - * regcache_mark_dirty: Mark the register cache as dirty + * regcache_mark_dirty: Indicate that HW registers were reset to default values * * @map: map to mark * - * Mark the register cache as dirty, for example due to the device - * having been powered down for suspend. If the cache is not marked - * as dirty then the cache sync will be suppressed. + * Inform regcache that the device has been powered down or reset, so that + * on resume, regcache_sync() knows to write out all non-default values + * stored in the cache. + * + * If this function is not called, regcache_sync() will assume that + * the hardware state still matches the cache state, modulo any writes that + * happened when cache_only was true. */ void regcache_mark_dirty(struct regmap *map) { map->lock(map->lock_arg); map->cache_dirty = true; + map->no_sync_defaults = true; map->unlock(map->lock_arg); } EXPORT_SYMBOL_GPL(regcache_mark_dirty); @@ -604,6 +614,9 @@ static int regcache_sync_block_single(struct regmap *map, void *block, { unsigned int i, regtmp, val; int ret; + bool no_sync_defaults = map->no_sync_defaults; + + map->no_sync_defaults = false; for (i = start; i < end; i++) { regtmp = block_base + (i * map->reg_stride); @@ -614,10 +627,12 @@ static int regcache_sync_block_single(struct regmap *map, void *block, val = regcache_get_val(map, block, i); - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret >= 0 && val == map->reg_defaults[ret].def) - continue; + if (no_sync_defaults) { + /* Is this the hardware default? If so skip. */ +
[PATCH V3 0/4] tas571x amplifier driver
V2->V3: Revert earlier changes to the regcache APIs. Change regcache_sync() so that regcache_mark_dirty() is used to indicate that the HW was reset. This allows tas571x (which does NOT call regcache_mark_dirty()) to use regcache_sync() to write back any register changes that occurred while in cache_only (tas571x pdn) mode. One assumption here is that regcache_sync() will be called once on resume, before any other writes. If it fails, the no_sync_defaults flag will be cleared and the next sync attempt, if any, will try to write out all contents of the cache. Kevin Cernekee (4): regmap: Use regcache_mark_dirty() to indicate power loss or reset ASoC: tas571x: Add DT binding document ASoC: tas571x: New driver for TI TAS571x power amplifiers MAINTAINERS: Add entry for tas571x ASoC codec driver .../devicetree/bindings/sound/tas571x.txt | 41 ++ MAINTAINERS| 6 + drivers/base/regmap/internal.h | 3 + drivers/base/regmap/regcache.c | 61 ++- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 520 + sound/soc/codecs/tas571x.h | 33 ++ 8 files changed, 651 insertions(+), 20 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3 3/4] ASoC: tas571x: New driver for TI TAS571x power amplifiers
Introduce a new codec driver for the Texas Instruments TAS5711/TAS5717/TAS5719 power amplifier chips. These chips are typically used to take an I2S digital audio input and drive 10-20W into a pair of speakers. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 520 + sound/soc/codecs/tas571x.h | 33 +++ 4 files changed, 560 insertions(+) create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 061c46587628..befff910d71a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TAS2552 if I2C select SND_SOC_TAS5086 if I2C + select SND_SOC_TAS571X if I2C select SND_SOC_TFA9879 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER @@ -611,6 +612,10 @@ config SND_SOC_TAS5086 tristate Texas Instruments TAS5086 speaker amplifier depends on I2C +config SND_SOC_TAS571X + tristate Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers + depends on I2C + config SND_SOC_TFA9879 tristate NXP Semiconductors TFA9879 amplifier depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index abe2d7edf65c..3dcf5ac85e89 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -106,6 +106,7 @@ snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o snd-soc-tas5086-objs := tas5086.o +snd-soc-tas571x-objs := tas571x.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o @@ -288,6 +289,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o +obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c new file mode 100644 index ..ffdf48397491 --- /dev/null +++ b/sound/soc/codecs/tas571x.c @@ -0,0 +1,520 @@ +/* + * TAS571x amplifier audio driver + * + * Copyright (C) 2015 Google, Inc. + * Copyright (c) 2013 Daniel Mack zon...@gmail.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include linux/clk.h +#include linux/delay.h +#include linux/device.h +#include linux/gpio/consumer.h +#include linux/i2c.h +#include linux/init.h +#include linux/kernel.h +#include linux/module.h +#include linux/of_device.h +#include linux/regmap.h +#include linux/regulator/consumer.h +#include linux/stddef.h +#include sound/pcm_params.h +#include sound/soc.h +#include sound/tlv.h + +#include tas571x.h + +#define TAS571X_MAX_SUPPLIES 6 + +struct tas571x_chip { + const char *const *supply_names; + int num_supply_names; + const struct snd_kcontrol_new *controls; + int num_controls; + const struct regmap_config *regmap_config; + int vol_reg_size; +}; + +struct tas571x_private { + const struct tas571x_chip *chip; + struct regmap *regmap; + struct regulator_bulk_data supplies[TAS571X_MAX_SUPPLIES]; + struct clk *mclk; + unsigned intformat; + struct gpio_desc*reset_gpio; + struct gpio_desc*pdn_gpio; + struct snd_soc_codec_driver codec_driver; +}; + +static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) +{ + switch (reg) { + case TAS571X_MVOL_REG: + case TAS571X_CH1_VOL_REG: + case TAS571X_CH2_VOL_REG: + return priv-chip-vol_reg_size; + default: + return 1; + } +} + +static int tas571x_reg_write(void *context, unsigned int reg, +unsigned int value) +{ + struct i2c_client *client = context; + struct tas571x_private *priv = i2c_get_clientdata(client); + unsigned int i, size; + uint8_t buf[5]; + int ret; + + size = tas571x_register_size(priv, reg); + buf[0] = reg; + + for (i = size; i = 1
[PATCH V3 1/4] regmap: Use regcache_mark_dirty() to indicate power loss or reset
Existing regmap users call regcache_mark_dirty() as part of the suspend/resume sequence, to tell regcache that non-default values need to be resynced post-resume. Add an internal no_sync_defaults regmap flag to remember this state, so that regcache_sync() can differentiate between these two cases: 1) HW was reset, so any cache values that match map-reg_defaults can be safely skipped. On some chips there are a lot of registers in the reg_defaults list, so this optimization speeds things up quite a bit. 2) HW was not reset (maybe it was just clock-gated), so if we cached any writes, they should be sent to the hardware regardless of whether they match the HW default. Currently this will write out all values in the regcache, since we don't maintain per-register dirty bits. Suggested-by: Mark Brown broo...@kernel.org Signed-off-by: Kevin Cernekee cerne...@chromium.org --- drivers/base/regmap/internal.h | 3 +++ drivers/base/regmap/regcache.c | 61 -- 2 files changed, 44 insertions(+), 20 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index a13587b5c2be..b2b2849fc6d3 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -131,7 +131,10 @@ struct regmap { struct reg_default *reg_defaults; const void *reg_defaults_raw; void *cache; + /* if set, the cache contains newer data than the HW */ u32 cache_dirty; + /* if set, the HW registers are known to match map-reg_defaults */ + bool no_sync_defaults; struct reg_default *patch; int patch_regs; diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 7eb7b3b98794..63af3103d0c6 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -253,6 +253,9 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, unsigned int max) { unsigned int reg; + bool no_sync_defaults = map-no_sync_defaults; + + map-no_sync_defaults = false; for (reg = min; reg = max; reg += map-reg_stride) { unsigned int val; @@ -266,10 +269,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, if (ret) return ret; - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, reg); - if (ret = 0 val == map-reg_defaults[ret].def) - continue; + if (no_sync_defaults) { + /* Is this the hardware default? If so skip. */ + ret = regcache_lookup_reg(map, reg); + if (ret = 0 val == map-reg_defaults[ret].def) + continue; + } map-cache_bypass = 1; ret = _regmap_write(map, reg, val); @@ -461,18 +466,23 @@ void regcache_cache_only(struct regmap *map, bool enable) EXPORT_SYMBOL_GPL(regcache_cache_only); /** - * regcache_mark_dirty: Mark the register cache as dirty + * regcache_mark_dirty: Indicate that HW registers were reset to default values * * @map: map to mark * - * Mark the register cache as dirty, for example due to the device - * having been powered down for suspend. If the cache is not marked - * as dirty then the cache sync will be suppressed. + * Inform regcache that the device has been powered down or reset, so that + * on resume, regcache_sync() knows to write out all non-default values + * stored in the cache. + * + * If this function is not called, regcache_sync() will assume that + * the hardware state still matches the cache state, modulo any writes that + * happened when cache_only was true. */ void regcache_mark_dirty(struct regmap *map) { map-lock(map-lock_arg); map-cache_dirty = true; + map-no_sync_defaults = true; map-unlock(map-lock_arg); } EXPORT_SYMBOL_GPL(regcache_mark_dirty); @@ -604,6 +614,9 @@ static int regcache_sync_block_single(struct regmap *map, void *block, { unsigned int i, regtmp, val; int ret; + bool no_sync_defaults = map-no_sync_defaults; + + map-no_sync_defaults = false; for (i = start; i end; i++) { regtmp = block_base + (i * map-reg_stride); @@ -614,10 +627,12 @@ static int regcache_sync_block_single(struct regmap *map, void *block, val = regcache_get_val(map, block, i); - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, regtmp); - if (ret = 0 val == map-reg_defaults[ret].def) - continue; + if (no_sync_defaults) { + /* Is this the hardware default? If so skip. */ + ret = regcache_lookup_reg(map, regtmp); + if (ret = 0 val == map
[PATCH V3 2/4] ASoC: tas571x: Add DT binding document
Document the bindings for the soon-to-be-added tas571x driver. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- .../devicetree/bindings/sound/tas571x.txt | 41 ++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt new file mode 100644 index ..0ac31d8d5ac4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tas571x.txt @@ -0,0 +1,41 @@ +Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers + +The codec is controlled through an I2C interface. It also has two other +signals that can be wired up to GPIOs: reset (strongly recommended), and +powerdown (optional). + +Required properties: + +- compatible: ti,tas5711, ti,tas5717, or ti,tas5719 +- reg: The I2C address of the device +- #sound-dai-cells: must be equal to 0 + +Optional properties: + +- reset-gpios: GPIO specifier for the TAS571x's active low reset line +- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line +- clocks: clock phandle for the MCLK input +- clock-names: should be mclk +- AVDD-supply: regulator phandle for the AVDD supply (all chips) +- DVDD-supply: regulator phandle for the DVDD supply (all chips) +- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719) +- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719) +- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719) +- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711) +- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711) +- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711) +- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711) + +Example: + + tas5717: audio-codec@2a { + compatible = ti,tas5717; + reg = 0x2a; + #sound-dai-cells = 0; + + reset-gpios = gpio5 1 GPIO_ACTIVE_LOW; + pdn-gpios = gpio5 2 GPIO_ACTIVE_LOW; + + clocks = clk_core CLK_I2S; + clock-names = mclk; + }; -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3 0/4] tas571x amplifier driver
V2-V3: Revert earlier changes to the regcache APIs. Change regcache_sync() so that regcache_mark_dirty() is used to indicate that the HW was reset. This allows tas571x (which does NOT call regcache_mark_dirty()) to use regcache_sync() to write back any register changes that occurred while in cache_only (tas571x pdn) mode. One assumption here is that regcache_sync() will be called once on resume, before any other writes. If it fails, the no_sync_defaults flag will be cleared and the next sync attempt, if any, will try to write out all contents of the cache. Kevin Cernekee (4): regmap: Use regcache_mark_dirty() to indicate power loss or reset ASoC: tas571x: Add DT binding document ASoC: tas571x: New driver for TI TAS571x power amplifiers MAINTAINERS: Add entry for tas571x ASoC codec driver .../devicetree/bindings/sound/tas571x.txt | 41 ++ MAINTAINERS| 6 + drivers/base/regmap/internal.h | 3 + drivers/base/regmap/regcache.c | 61 ++- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 520 + sound/soc/codecs/tas571x.h | 33 ++ 8 files changed, 651 insertions(+), 20 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V3 4/4] MAINTAINERS: Add entry for tas571x ASoC codec driver
Add self as maintainer for the new driver. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- MAINTAINERS | 6 ++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ea0001760035..15153fc37cc4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9878,6 +9878,12 @@ L: net...@vger.kernel.org S: Maintained F: drivers/net/ethernet/ti/netcp* +TI TAS571X FAMILY ASoC CODEC DRIVER +M: Kevin Cernekee cerne...@chromium.org +L: alsa-de...@alsa-project.org (moderated for non-subscribers) +S: Odd Fixes +F: sound/soc/codecs/tas571x* + TI TWL4030 SERIES SOC CODEC DRIVER M: Peter Ujfalusi peter.ujfal...@ti.com L: alsa-de...@alsa-project.org (moderated for non-subscribers) -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V2 1/4] regmap: cache: Add "was_reset" argument to regcache_sync_region()
On Wed, Apr 29, 2015 at 9:46 AM, Mark Brown wrote: > On Wed, Apr 29, 2015 at 07:13:27AM -0700, Kevin Cernekee wrote: >> On Wed, Apr 29, 2015 at 3:40 AM, Mark Brown wrote: > >> > Like I said above we can tell if the hardware was reset because >> > mark_dirty() is called. > >> That covers the public API, but I do not understand how you intended >> for this data to be stored in the rbtree if the use of a dirty bitmask >> is discouraged. > > We just need a single boolean? Right, so if we add a per-regmap bool that tells us whether the device has been reset, then in the case of "not reset" we will have to write every regcache entry out to the device. Even the ones that weren't touched while in cache_only mode. This makes the "not reset" case much less efficient than the "reset" case. Maybe that's good enough for most purposes. It's no worse than what my original patch submission did, anyway. BTW, any preferences on naming for the bool or for the renamed mark_dirty function? >> i.e. regcache_sync() finds a register value marked "present". How do >> we know whether we need to write it back to the hardware? For the >> special case of "cached non default register values immediately after >> a HW reset" you can mostly figure this out, but if there was no HW >> reset how do we know which entries changed while the HW was >> inaccessible? > > In the first instance do we care? I'm not sure I understand the question. >> > I'm not suggesting that we do anything based on the presence of a cache >> > entry, I'm suggesting that we could avoid having to ever cache values >> > that never get referenced on a system (which can be a lot of them for >> > common use cases) saving us memory. > >> This seems to be solving a different problem. It sounds like you are >> more worried about regcache_sync() writing back lots of default values >> for registers that were never touched, than performing unnecessary >> writes to a few (actively used) registers that weren't changed while >> we were in cache_only mode. Is that accurate? > > No. This is nothing to do with sync, it's just something that might be > nice. Thanks, that clarifies things. I was not aware that other drivers even had an issue with excessively large regcache rbtrees, as my reg_defaults list is short. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V2 1/4] regmap: cache: Add "was_reset" argument to regcache_sync_region()
On Wed, Apr 29, 2015 at 3:40 AM, Mark Brown wrote: > On Tue, Apr 28, 2015 at 09:58:48PM -0700, Kevin Cernekee wrote: >> On Sat, Apr 25, 2015 at 4:32 AM, Mark Brown wrote: > >> > What we should be doing here is providing a way for users to tell regmap >> > if they've reset the register map and actually we already have that >> > interface, it's just not got the best name - regcache_mark_dirty() is >> > effectively it since there's really not a lot of other reasons why a >> > driver would need to mark the cache as dirty. We're just not handling > >> 1) How do we tell the difference between "regcache contains a >> non-default value that correctly reflects the hardware register >> contents" versus "regcache contains a non-default value that is >> waiting to be written when we exit cache_only mode"? > > Like I said above we can tell if the hardware was reset because > mark_dirty() is called. That covers the public API, but I do not understand how you intended for this data to be stored in the rbtree if the use of a dirty bitmask is discouraged. i.e. regcache_sync() finds a register value marked "present". How do we know whether we need to write it back to the hardware? For the special case of "cached non default register values immediately after a HW reset" you can mostly figure this out, but if there was no HW reset how do we know which entries changed while the HW was inaccessible? > I'm not suggesting that we do anything based on the presence of a cache > entry, I'm suggesting that we could avoid having to ever cache values > that never get referenced on a system (which can be a lot of them for > common use cases) saving us memory. This seems to be solving a different problem. It sounds like you are more worried about regcache_sync() writing back lots of default values for registers that were never touched, than performing unnecessary writes to a few (actively used) registers that weren't changed while we were in cache_only mode. Is that accurate? FWIW, in the current iteration of the tas571x driver, there are few if any registers that meet this criteria. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V2 1/4] regmap: cache: Add was_reset argument to regcache_sync_region()
On Wed, Apr 29, 2015 at 9:46 AM, Mark Brown broo...@kernel.org wrote: On Wed, Apr 29, 2015 at 07:13:27AM -0700, Kevin Cernekee wrote: On Wed, Apr 29, 2015 at 3:40 AM, Mark Brown broo...@kernel.org wrote: Like I said above we can tell if the hardware was reset because mark_dirty() is called. That covers the public API, but I do not understand how you intended for this data to be stored in the rbtree if the use of a dirty bitmask is discouraged. We just need a single boolean? Right, so if we add a per-regmap bool that tells us whether the device has been reset, then in the case of not reset we will have to write every regcache entry out to the device. Even the ones that weren't touched while in cache_only mode. This makes the not reset case much less efficient than the reset case. Maybe that's good enough for most purposes. It's no worse than what my original patch submission did, anyway. BTW, any preferences on naming for the bool or for the renamed mark_dirty function? i.e. regcache_sync() finds a register value marked present. How do we know whether we need to write it back to the hardware? For the special case of cached non default register values immediately after a HW reset you can mostly figure this out, but if there was no HW reset how do we know which entries changed while the HW was inaccessible? In the first instance do we care? I'm not sure I understand the question. I'm not suggesting that we do anything based on the presence of a cache entry, I'm suggesting that we could avoid having to ever cache values that never get referenced on a system (which can be a lot of them for common use cases) saving us memory. This seems to be solving a different problem. It sounds like you are more worried about regcache_sync() writing back lots of default values for registers that were never touched, than performing unnecessary writes to a few (actively used) registers that weren't changed while we were in cache_only mode. Is that accurate? No. This is nothing to do with sync, it's just something that might be nice. Thanks, that clarifies things. I was not aware that other drivers even had an issue with excessively large regcache rbtrees, as my reg_defaults list is short. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V2 1/4] regmap: cache: Add was_reset argument to regcache_sync_region()
On Wed, Apr 29, 2015 at 3:40 AM, Mark Brown broo...@kernel.org wrote: On Tue, Apr 28, 2015 at 09:58:48PM -0700, Kevin Cernekee wrote: On Sat, Apr 25, 2015 at 4:32 AM, Mark Brown broo...@kernel.org wrote: What we should be doing here is providing a way for users to tell regmap if they've reset the register map and actually we already have that interface, it's just not got the best name - regcache_mark_dirty() is effectively it since there's really not a lot of other reasons why a driver would need to mark the cache as dirty. We're just not handling 1) How do we tell the difference between regcache contains a non-default value that correctly reflects the hardware register contents versus regcache contains a non-default value that is waiting to be written when we exit cache_only mode? Like I said above we can tell if the hardware was reset because mark_dirty() is called. That covers the public API, but I do not understand how you intended for this data to be stored in the rbtree if the use of a dirty bitmask is discouraged. i.e. regcache_sync() finds a register value marked present. How do we know whether we need to write it back to the hardware? For the special case of cached non default register values immediately after a HW reset you can mostly figure this out, but if there was no HW reset how do we know which entries changed while the HW was inaccessible? I'm not suggesting that we do anything based on the presence of a cache entry, I'm suggesting that we could avoid having to ever cache values that never get referenced on a system (which can be a lot of them for common use cases) saving us memory. This seems to be solving a different problem. It sounds like you are more worried about regcache_sync() writing back lots of default values for registers that were never touched, than performing unnecessary writes to a few (actively used) registers that weren't changed while we were in cache_only mode. Is that accurate? FWIW, in the current iteration of the tas571x driver, there are few if any registers that meet this criteria. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V2 1/4] regmap: cache: Add "was_reset" argument to regcache_sync_region()
On Sat, Apr 25, 2015 at 4:32 AM, Mark Brown wrote: > On Fri, Apr 24, 2015 at 03:36:45PM -0700, Kevin Cernekee wrote: > >> index 116655d92269..ece122a6fdeb 100644 >> --- a/include/linux/regmap.h >> +++ b/include/linux/regmap.h >> @@ -438,7 +438,7 @@ bool regmap_can_raw_write(struct regmap *map); >> >> int regcache_sync(struct regmap *map); >> int regcache_sync_region(struct regmap *map, unsigned int min, >> - unsigned int max); >> + unsigned int max, bool was_reset); > > This seems pretty ugly - both the fact that we're changing the signature > of the function and the naming of the argument feel inelegant. The > point isn't if the device has been reset, the point is if the device > currently has the default register values or not, and this means that > the user is responsible for tracking that state until the next time it > does the sync. That may be immediately like in your case but there's no > reason that has to be the case. The fact that we're passing in > something called "is_reset" which sounds like a state value for the > register map is a bit of a warning sign here. > > What we should be doing here is providing a way for users to tell regmap > if they've reset the register map and actually we already have that > interface, it's just not got the best name - regcache_mark_dirty() is > effectively it since there's really not a lot of other reasons why a > driver would need to mark the cache as dirty. We're just not handling > it properly. What we should do instead is to keep the interface as it > is for now and make it behave in a more expected fashion so that if the > cache is explicitly marked dirty we assume that the hardware is in the > default state and otherwise we don't. > > Ideally what we'd do is both improve the naming of mark_dirty() (though > that's API churn which is nasty) and arrange for rbtree to cache the > default values lazily, that way the only things in the cache will be > things that have been explicitly changed (we will still want default > checking but it makes life easier and means we don't end up having to do > a full writeout for cases where things have been put into cache mode > without a reset). Hi Mark, I started prototyping this, but ran into a couple of issues: 1) How do we tell the difference between "regcache contains a non-default value that correctly reflects the hardware register contents" versus "regcache contains a non-default value that is waiting to be written when we exit cache_only mode"? 2) Does that also mean that we should store default values in the rbtree if they are part of a deferred cache_only write, but not store them if the write went through to the hardware? 3) If we're caching the default values lazily, does that mean that every regcache read would incur both an rbtree lookup and a bsearch of the reg_defaults array? 4) If "the only things in the cache will be things that have been explicitly changed," that could impact the semantics of regcache_drop_region(). Which fortunately has no users. Seems like it would be more straightforward just to add an rbnode->dirty bitmask alongside rbnode->cache_present, rather than trying to infer the hardware state from the presence/absence of the cache entry. Knowing whether each individual register is out of sync with the hardware lets us avoid unnecessary writes in both situations: full reset, and temporary loss of register access. What do you think? -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] MIPS: BMIPS: Delete unused Kconfig symbol
This was left over from an earlier iteration of the BMIPS irqchip changes. It doesn't actually have an effect, so let's nuke it. Reported-by: Valentin Rothberg Signed-off-by: Kevin Cernekee --- Ralf - could you please pull this for 4.1? arch/mips/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index f5016656494f..19e5d40fdf40 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -147,7 +147,6 @@ config BMIPS_GENERIC select BCM7120_L2_IRQ select BRCMSTB_L2_IRQ select IRQ_CPU - select RAW_IRQ_ACCESSORS select DMA_NONCOHERENT select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V2 1/4] regmap: cache: Add was_reset argument to regcache_sync_region()
On Sat, Apr 25, 2015 at 4:32 AM, Mark Brown broo...@kernel.org wrote: On Fri, Apr 24, 2015 at 03:36:45PM -0700, Kevin Cernekee wrote: index 116655d92269..ece122a6fdeb 100644 --- a/include/linux/regmap.h +++ b/include/linux/regmap.h @@ -438,7 +438,7 @@ bool regmap_can_raw_write(struct regmap *map); int regcache_sync(struct regmap *map); int regcache_sync_region(struct regmap *map, unsigned int min, - unsigned int max); + unsigned int max, bool was_reset); This seems pretty ugly - both the fact that we're changing the signature of the function and the naming of the argument feel inelegant. The point isn't if the device has been reset, the point is if the device currently has the default register values or not, and this means that the user is responsible for tracking that state until the next time it does the sync. That may be immediately like in your case but there's no reason that has to be the case. The fact that we're passing in something called is_reset which sounds like a state value for the register map is a bit of a warning sign here. What we should be doing here is providing a way for users to tell regmap if they've reset the register map and actually we already have that interface, it's just not got the best name - regcache_mark_dirty() is effectively it since there's really not a lot of other reasons why a driver would need to mark the cache as dirty. We're just not handling it properly. What we should do instead is to keep the interface as it is for now and make it behave in a more expected fashion so that if the cache is explicitly marked dirty we assume that the hardware is in the default state and otherwise we don't. Ideally what we'd do is both improve the naming of mark_dirty() (though that's API churn which is nasty) and arrange for rbtree to cache the default values lazily, that way the only things in the cache will be things that have been explicitly changed (we will still want default checking but it makes life easier and means we don't end up having to do a full writeout for cases where things have been put into cache mode without a reset). Hi Mark, I started prototyping this, but ran into a couple of issues: 1) How do we tell the difference between regcache contains a non-default value that correctly reflects the hardware register contents versus regcache contains a non-default value that is waiting to be written when we exit cache_only mode? 2) Does that also mean that we should store default values in the rbtree if they are part of a deferred cache_only write, but not store them if the write went through to the hardware? 3) If we're caching the default values lazily, does that mean that every regcache read would incur both an rbtree lookup and a bsearch of the reg_defaults array? 4) If the only things in the cache will be things that have been explicitly changed, that could impact the semantics of regcache_drop_region(). Which fortunately has no users. Seems like it would be more straightforward just to add an rbnode-dirty bitmask alongside rbnode-cache_present, rather than trying to infer the hardware state from the presence/absence of the cache entry. Knowing whether each individual register is out of sync with the hardware lets us avoid unnecessary writes in both situations: full reset, and temporary loss of register access. What do you think? -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH] MIPS: BMIPS: Delete unused Kconfig symbol
This was left over from an earlier iteration of the BMIPS irqchip changes. It doesn't actually have an effect, so let's nuke it. Reported-by: Valentin Rothberg valentinrothb...@gmail.com Signed-off-by: Kevin Cernekee cerne...@chromium.org --- Ralf - could you please pull this for 4.1? arch/mips/Kconfig | 1 - 1 file changed, 1 deletion(-) diff --git a/arch/mips/Kconfig b/arch/mips/Kconfig index f5016656494f..19e5d40fdf40 100644 --- a/arch/mips/Kconfig +++ b/arch/mips/Kconfig @@ -147,7 +147,6 @@ config BMIPS_GENERIC select BCM7120_L2_IRQ select BRCMSTB_L2_IRQ select IRQ_CPU - select RAW_IRQ_ACCESSORS select DMA_NONCOHERENT select SYS_SUPPORTS_32BIT_KERNEL select SYS_SUPPORTS_LITTLE_ENDIAN -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V2 1/4] regmap: cache: Add "was_reset" argument to regcache_sync_region()
On Fri, Apr 24, 2015 at 3:36 PM, Kevin Cernekee wrote: > regcache_sync() and regcache_sync_region() currently assume that the > hardware has just emerged from a clean reset, and that all registers are > in their default states. But that isn't the only possibility; the device > may have been in a different state in which the registers were > inaccessible but have retained their contents, e.g. clock gating. > > So we will extend the more versatile of the two functions, > regcache_sync_region(), to let the caller decide what assumptions should > be made. > > One driver that can benefit from this is adau1977, which has hacks to > overwrite the registers that regcache_sync() might have missed. Also, > the powerdown pin on tas571x does not reset the register contents either, > so a similar feature will be required by that driver. > > This commit just adds the new argument by changing the function > declarations and call sites, but doesn't wire it up yet. The last two lines of the changelog were inadvertently carried over from an older version of the patch, and should be deleted. Will fix in V3. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2 2/4] ASoC: tas571x: Add DT binding document
Document the bindings for the soon-to-be-added tas571x driver. Signed-off-by: Kevin Cernekee --- .../devicetree/bindings/sound/tas571x.txt | 41 ++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt new file mode 100644 index ..0ac31d8d5ac4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tas571x.txt @@ -0,0 +1,41 @@ +Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers + +The codec is controlled through an I2C interface. It also has two other +signals that can be wired up to GPIOs: reset (strongly recommended), and +powerdown (optional). + +Required properties: + +- compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719" +- reg: The I2C address of the device +- #sound-dai-cells: must be equal to 0 + +Optional properties: + +- reset-gpios: GPIO specifier for the TAS571x's active low reset line +- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line +- clocks: clock phandle for the MCLK input +- clock-names: should be "mclk" +- AVDD-supply: regulator phandle for the AVDD supply (all chips) +- DVDD-supply: regulator phandle for the DVDD supply (all chips) +- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719) +- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719) +- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719) +- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711) +- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711) +- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711) +- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711) + +Example: + + tas5717: audio-codec@2a { + compatible = "ti,tas5717"; + reg = <0x2a>; + #sound-dai-cells = <0>; + + reset-gpios = < 1 GPIO_ACTIVE_LOW>; + pdn-gpios = < 2 GPIO_ACTIVE_LOW>; + + clocks = <_core CLK_I2S>; + clock-names = "mclk"; + }; -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2 4/4] MAINTAINERS: Add entry for tas571x ASoC codec driver
Add self as maintainer for the new driver. Signed-off-by: Kevin Cernekee --- MAINTAINERS | 6 ++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ea0001760035..15153fc37cc4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9878,6 +9878,12 @@ L: net...@vger.kernel.org S: Maintained F: drivers/net/ethernet/ti/netcp* +TI TAS571X FAMILY ASoC CODEC DRIVER +M: Kevin Cernekee +L: alsa-de...@alsa-project.org (moderated for non-subscribers) +S: Odd Fixes +F: sound/soc/codecs/tas571x* + TI TWL4030 SERIES SOC CODEC DRIVER M: Peter Ujfalusi L: alsa-de...@alsa-project.org (moderated for non-subscribers) -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2 1/4] regmap: cache: Add "was_reset" argument to regcache_sync_region()
regcache_sync() and regcache_sync_region() currently assume that the hardware has just emerged from a clean reset, and that all registers are in their default states. But that isn't the only possibility; the device may have been in a different state in which the registers were inaccessible but have retained their contents, e.g. clock gating. So we will extend the more versatile of the two functions, regcache_sync_region(), to let the caller decide what assumptions should be made. One driver that can benefit from this is adau1977, which has hacks to overwrite the registers that regcache_sync() might have missed. Also, the powerdown pin on tas571x does not reset the register contents either, so a similar feature will be required by that driver. This commit just adds the new argument by changing the function declarations and call sites, but doesn't wire it up yet. Signed-off-by: Kevin Cernekee --- drivers/base/regmap/internal.h| 5 ++- drivers/base/regmap/regcache-lzo.c| 2 +- drivers/base/regmap/regcache-rbtree.c | 5 ++- drivers/base/regmap/regcache.c| 75 --- drivers/media/radio/radio-si476x.c| 18 ++--- drivers/mfd/wm8994-core.c | 5 ++- include/linux/regmap.h| 4 +- include/sound/hda_regmap.h| 3 +- sound/soc/codecs/wm8962.c | 3 +- 9 files changed, 72 insertions(+), 48 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index a13587b5c2be..89dfefeb168e 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -155,7 +155,8 @@ struct regcache_ops { #endif int (*read)(struct regmap *map, unsigned int reg, unsigned int *value); int (*write)(struct regmap *map, unsigned int reg, unsigned int value); - int (*sync)(struct regmap *map, unsigned int min, unsigned int max); + int (*sync)(struct regmap *map, unsigned int min, unsigned int max, + bool was_reset); int (*drop)(struct regmap *map, unsigned int min, unsigned int max); }; @@ -215,7 +216,7 @@ int regcache_sync(struct regmap *map); int regcache_sync_block(struct regmap *map, void *block, unsigned long *cache_present, unsigned int block_base, unsigned int start, - unsigned int end); + unsigned int end, bool was_reset); static inline const void *regcache_get_val_addr(struct regmap *map, const void *base, diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c index 2d53f6f138e1..52ed0d03ce69 100644 --- a/drivers/base/regmap/regcache-lzo.c +++ b/drivers/base/regmap/regcache-lzo.c @@ -332,7 +332,7 @@ out: } static int regcache_lzo_sync(struct regmap *map, unsigned int min, -unsigned int max) +unsigned int max, bool was_reset) { struct regcache_lzo_ctx **lzo_blocks; unsigned int val; diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 81751a49d8bf..8fc1727e635c 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -445,7 +445,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, } static int regcache_rbtree_sync(struct regmap *map, unsigned int min, - unsigned int max) + unsigned int max, bool was_reset) { struct regcache_rbtree_ctx *rbtree_ctx; struct rb_node *node; @@ -477,7 +477,8 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min, ret = regcache_sync_block(map, rbnode->block, rbnode->cache_present, - rbnode->base_reg, start, end); + rbnode->base_reg, start, end, + was_reset); if (ret != 0) return ret; } diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 7eb7b3b98794..d27b45f50497 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -250,7 +250,7 @@ int regcache_write(struct regmap *map, } static int regcache_default_sync(struct regmap *map, unsigned int min, -unsigned int max) +unsigned int max, bool was_reset) { unsigned int reg; @@ -266,10 +266,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, if (ret) return ret; - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, reg); - if (ret >= 0 && val == map
[PATCH V2 3/4] ASoC: tas571x: New driver for TI TAS571x power amplifiers
Introduce a new codec driver for the Texas Instruments TAS5711/TAS5717/TAS5719 power amplifier chips. These chips are typically used to take an I2S digital audio input and drive 10-20W into a pair of speakers. Signed-off-by: Kevin Cernekee --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 521 + sound/soc/codecs/tas571x.h | 33 +++ 4 files changed, 561 insertions(+) create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 061c46587628..befff910d71a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TAS2552 if I2C select SND_SOC_TAS5086 if I2C + select SND_SOC_TAS571X if I2C select SND_SOC_TFA9879 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER @@ -611,6 +612,10 @@ config SND_SOC_TAS5086 tristate "Texas Instruments TAS5086 speaker amplifier" depends on I2C +config SND_SOC_TAS571X + tristate "Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers" + depends on I2C + config SND_SOC_TFA9879 tristate "NXP Semiconductors TFA9879 amplifier" depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index abe2d7edf65c..3dcf5ac85e89 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -106,6 +106,7 @@ snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o snd-soc-tas5086-objs := tas5086.o +snd-soc-tas571x-objs := tas571x.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o @@ -288,6 +289,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o +obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c new file mode 100644 index ..08e358638f2e --- /dev/null +++ b/sound/soc/codecs/tas571x.c @@ -0,0 +1,521 @@ +/* + * TAS571x amplifier audio driver + * + * Copyright (C) 2015 Google, Inc. + * Copyright (c) 2013 Daniel Mack + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "tas571x.h" + +#define TAS571X_MAX_SUPPLIES 6 + +struct tas571x_chip { + const char *const *supply_names; + int num_supply_names; + const struct snd_kcontrol_new *controls; + int num_controls; + const struct regmap_config *regmap_config; + int vol_reg_size; +}; + +struct tas571x_private { + const struct tas571x_chip *chip; + struct regmap *regmap; + struct regulator_bulk_data supplies[TAS571X_MAX_SUPPLIES]; + struct clk *mclk; + unsigned intformat; + struct gpio_desc*reset_gpio; + struct gpio_desc*pdn_gpio; + struct snd_soc_codec_driver codec_driver; +}; + +static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) +{ + switch (reg) { + case TAS571X_MVOL_REG: + case TAS571X_CH1_VOL_REG: + case TAS571X_CH2_VOL_REG: + return priv->chip->vol_reg_size; + default: + return 1; + } +} + +static int tas571x_reg_write(void *context, unsigned int reg, +unsigned int value) +{ + struct i2c_client *client = context; + struct tas571x_private *priv = i2c_get_clientdata(client); + unsigned int i, size; + uint8_t buf[5]; + int ret; + + size = tas571x_register_size(priv, reg); + buf[0] = reg; + + for (i = size; i >= 1; --i) { + buf[i] = value; + value >>= 8; + } + + ret = i2c_master_send(client, buf, size + 1); + if (ret == size + 1) + return
[PATCH V2 0/4] tas571x amplifier driver
V1->V2: - Incorporate changes from review feedback - Change GPIOs to active low - Create a tas571x_chip struct to capture the growing list of differences between 5711 and 5717/5719 - Add register defaults for each chip - Extend regcache_sync_region() to allow it to sync with hardware registers that don't contain their power-on-reset values Kevin Cernekee (4): regmap: cache: Add "was_reset" argument to regcache_sync_region() ASoC: tas571x: Add DT binding document ASoC: tas571x: New driver for TI TAS571x power amplifiers MAINTAINERS: Add entry for tas571x ASoC codec driver .../devicetree/bindings/sound/tas571x.txt | 41 ++ MAINTAINERS| 6 + drivers/base/regmap/internal.h | 5 +- drivers/base/regmap/regcache-lzo.c | 2 +- drivers/base/regmap/regcache-rbtree.c | 5 +- drivers/base/regmap/regcache.c | 75 +-- drivers/media/radio/radio-si476x.c | 18 +- drivers/mfd/wm8994-core.c | 5 +- include/linux/regmap.h | 4 +- include/sound/hda_regmap.h | 3 +- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 521 + sound/soc/codecs/tas571x.h | 33 ++ sound/soc/codecs/wm8962.c | 3 +- 15 files changed, 680 insertions(+), 48 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 2/3] ASoC: tas571x: New driver for TI TAS571x power amplifiers
On Fri, Apr 24, 2015 at 2:28 AM, Mark Brown wrote: > On Thu, Apr 23, 2015 at 05:47:49PM -0700, Kevin Cernekee wrote: > >> This is mostly working OK, but regcache_sync() assumes that the >> hardware registers have been reset back to the default values. The >> "pdn" GPIO doesn't actually reset the state of the tas571x; it just >> makes I2C inaccessible and inhibits audio output. So if the factory >> default for mute is 0, corner cases like this fail: > > ... > >> Aside from unnecessarily pulsing the reset GPIO when transitioning >> back from SND_SOC_BIAS_OFF or overriding regcache_default_sync(), can >> you think of a way to work around this? > > Do you need to work around it? If the register map is being perserved > you don't need to sync so just don't do it - it's just that the normal > expectation would be that power down would cause the register map to be > reset. How do I tell regcache to write out any updates that happened while the hardware was inaccessible? I see that regmap->cache_dirty is 1, but nothing flushes it automatically when exiting cache_only mode. -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH 2/3] ASoC: tas571x: New driver for TI TAS571x power amplifiers
On Fri, Apr 24, 2015 at 2:28 AM, Mark Brown broo...@kernel.org wrote: On Thu, Apr 23, 2015 at 05:47:49PM -0700, Kevin Cernekee wrote: This is mostly working OK, but regcache_sync() assumes that the hardware registers have been reset back to the default values. The pdn GPIO doesn't actually reset the state of the tas571x; it just makes I2C inaccessible and inhibits audio output. So if the factory default for mute is 0, corner cases like this fail: ... Aside from unnecessarily pulsing the reset GPIO when transitioning back from SND_SOC_BIAS_OFF or overriding regcache_default_sync(), can you think of a way to work around this? Do you need to work around it? If the register map is being perserved you don't need to sync so just don't do it - it's just that the normal expectation would be that power down would cause the register map to be reset. How do I tell regcache to write out any updates that happened while the hardware was inaccessible? I see that regmap-cache_dirty is 1, but nothing flushes it automatically when exiting cache_only mode. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2 0/4] tas571x amplifier driver
V1-V2: - Incorporate changes from review feedback - Change GPIOs to active low - Create a tas571x_chip struct to capture the growing list of differences between 5711 and 5717/5719 - Add register defaults for each chip - Extend regcache_sync_region() to allow it to sync with hardware registers that don't contain their power-on-reset values Kevin Cernekee (4): regmap: cache: Add was_reset argument to regcache_sync_region() ASoC: tas571x: Add DT binding document ASoC: tas571x: New driver for TI TAS571x power amplifiers MAINTAINERS: Add entry for tas571x ASoC codec driver .../devicetree/bindings/sound/tas571x.txt | 41 ++ MAINTAINERS| 6 + drivers/base/regmap/internal.h | 5 +- drivers/base/regmap/regcache-lzo.c | 2 +- drivers/base/regmap/regcache-rbtree.c | 5 +- drivers/base/regmap/regcache.c | 75 +-- drivers/media/radio/radio-si476x.c | 18 +- drivers/mfd/wm8994-core.c | 5 +- include/linux/regmap.h | 4 +- include/sound/hda_regmap.h | 3 +- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 521 + sound/soc/codecs/tas571x.h | 33 ++ sound/soc/codecs/wm8962.c | 3 +- 15 files changed, 680 insertions(+), 48 deletions(-) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2 3/4] ASoC: tas571x: New driver for TI TAS571x power amplifiers
Introduce a new codec driver for the Texas Instruments TAS5711/TAS5717/TAS5719 power amplifier chips. These chips are typically used to take an I2S digital audio input and drive 10-20W into a pair of speakers. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- sound/soc/codecs/Kconfig | 5 + sound/soc/codecs/Makefile | 2 + sound/soc/codecs/tas571x.c | 521 + sound/soc/codecs/tas571x.h | 33 +++ 4 files changed, 561 insertions(+) create mode 100644 sound/soc/codecs/tas571x.c create mode 100644 sound/soc/codecs/tas571x.h diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig index 061c46587628..befff910d71a 100644 --- a/sound/soc/codecs/Kconfig +++ b/sound/soc/codecs/Kconfig @@ -104,6 +104,7 @@ config SND_SOC_ALL_CODECS select SND_SOC_STAC9766 if SND_SOC_AC97_BUS select SND_SOC_TAS2552 if I2C select SND_SOC_TAS5086 if I2C + select SND_SOC_TAS571X if I2C select SND_SOC_TFA9879 if I2C select SND_SOC_TLV320AIC23_I2C if I2C select SND_SOC_TLV320AIC23_SPI if SPI_MASTER @@ -611,6 +612,10 @@ config SND_SOC_TAS5086 tristate Texas Instruments TAS5086 speaker amplifier depends on I2C +config SND_SOC_TAS571X + tristate Texas Instruments TAS5711/TAS5717/TAS5719 power amplifiers + depends on I2C + config SND_SOC_TFA9879 tristate NXP Semiconductors TFA9879 amplifier depends on I2C diff --git a/sound/soc/codecs/Makefile b/sound/soc/codecs/Makefile index abe2d7edf65c..3dcf5ac85e89 100644 --- a/sound/soc/codecs/Makefile +++ b/sound/soc/codecs/Makefile @@ -106,6 +106,7 @@ snd-soc-sta350-objs := sta350.o snd-soc-sta529-objs := sta529.o snd-soc-stac9766-objs := stac9766.o snd-soc-tas5086-objs := tas5086.o +snd-soc-tas571x-objs := tas571x.o snd-soc-tfa9879-objs := tfa9879.o snd-soc-tlv320aic23-objs := tlv320aic23.o snd-soc-tlv320aic23-i2c-objs := tlv320aic23-i2c.o @@ -288,6 +289,7 @@ obj-$(CONFIG_SND_SOC_STA529) += snd-soc-sta529.o obj-$(CONFIG_SND_SOC_STAC9766) += snd-soc-stac9766.o obj-$(CONFIG_SND_SOC_TAS2552) += snd-soc-tas2552.o obj-$(CONFIG_SND_SOC_TAS5086) += snd-soc-tas5086.o +obj-$(CONFIG_SND_SOC_TAS571X) += snd-soc-tas571x.o obj-$(CONFIG_SND_SOC_TFA9879) += snd-soc-tfa9879.o obj-$(CONFIG_SND_SOC_TLV320AIC23) += snd-soc-tlv320aic23.o obj-$(CONFIG_SND_SOC_TLV320AIC23_I2C) += snd-soc-tlv320aic23-i2c.o diff --git a/sound/soc/codecs/tas571x.c b/sound/soc/codecs/tas571x.c new file mode 100644 index ..08e358638f2e --- /dev/null +++ b/sound/soc/codecs/tas571x.c @@ -0,0 +1,521 @@ +/* + * TAS571x amplifier audio driver + * + * Copyright (C) 2015 Google, Inc. + * Copyright (c) 2013 Daniel Mack zon...@gmail.com + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + */ + +#include linux/clk.h +#include linux/delay.h +#include linux/device.h +#include linux/gpio/consumer.h +#include linux/i2c.h +#include linux/init.h +#include linux/kernel.h +#include linux/module.h +#include linux/of_device.h +#include linux/regmap.h +#include linux/regulator/consumer.h +#include linux/stddef.h +#include sound/pcm_params.h +#include sound/soc.h +#include sound/tlv.h + +#include tas571x.h + +#define TAS571X_MAX_SUPPLIES 6 + +struct tas571x_chip { + const char *const *supply_names; + int num_supply_names; + const struct snd_kcontrol_new *controls; + int num_controls; + const struct regmap_config *regmap_config; + int vol_reg_size; +}; + +struct tas571x_private { + const struct tas571x_chip *chip; + struct regmap *regmap; + struct regulator_bulk_data supplies[TAS571X_MAX_SUPPLIES]; + struct clk *mclk; + unsigned intformat; + struct gpio_desc*reset_gpio; + struct gpio_desc*pdn_gpio; + struct snd_soc_codec_driver codec_driver; +}; + +static int tas571x_register_size(struct tas571x_private *priv, unsigned int reg) +{ + switch (reg) { + case TAS571X_MVOL_REG: + case TAS571X_CH1_VOL_REG: + case TAS571X_CH2_VOL_REG: + return priv-chip-vol_reg_size; + default: + return 1; + } +} + +static int tas571x_reg_write(void *context, unsigned int reg, +unsigned int value) +{ + struct i2c_client *client = context; + struct tas571x_private *priv = i2c_get_clientdata(client); + unsigned int i, size; + uint8_t buf[5]; + int ret; + + size = tas571x_register_size(priv, reg); + buf[0] = reg; + + for (i = size; i = 1
[PATCH V2 1/4] regmap: cache: Add was_reset argument to regcache_sync_region()
regcache_sync() and regcache_sync_region() currently assume that the hardware has just emerged from a clean reset, and that all registers are in their default states. But that isn't the only possibility; the device may have been in a different state in which the registers were inaccessible but have retained their contents, e.g. clock gating. So we will extend the more versatile of the two functions, regcache_sync_region(), to let the caller decide what assumptions should be made. One driver that can benefit from this is adau1977, which has hacks to overwrite the registers that regcache_sync() might have missed. Also, the powerdown pin on tas571x does not reset the register contents either, so a similar feature will be required by that driver. This commit just adds the new argument by changing the function declarations and call sites, but doesn't wire it up yet. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- drivers/base/regmap/internal.h| 5 ++- drivers/base/regmap/regcache-lzo.c| 2 +- drivers/base/regmap/regcache-rbtree.c | 5 ++- drivers/base/regmap/regcache.c| 75 --- drivers/media/radio/radio-si476x.c| 18 ++--- drivers/mfd/wm8994-core.c | 5 ++- include/linux/regmap.h| 4 +- include/sound/hda_regmap.h| 3 +- sound/soc/codecs/wm8962.c | 3 +- 9 files changed, 72 insertions(+), 48 deletions(-) diff --git a/drivers/base/regmap/internal.h b/drivers/base/regmap/internal.h index a13587b5c2be..89dfefeb168e 100644 --- a/drivers/base/regmap/internal.h +++ b/drivers/base/regmap/internal.h @@ -155,7 +155,8 @@ struct regcache_ops { #endif int (*read)(struct regmap *map, unsigned int reg, unsigned int *value); int (*write)(struct regmap *map, unsigned int reg, unsigned int value); - int (*sync)(struct regmap *map, unsigned int min, unsigned int max); + int (*sync)(struct regmap *map, unsigned int min, unsigned int max, + bool was_reset); int (*drop)(struct regmap *map, unsigned int min, unsigned int max); }; @@ -215,7 +216,7 @@ int regcache_sync(struct regmap *map); int regcache_sync_block(struct regmap *map, void *block, unsigned long *cache_present, unsigned int block_base, unsigned int start, - unsigned int end); + unsigned int end, bool was_reset); static inline const void *regcache_get_val_addr(struct regmap *map, const void *base, diff --git a/drivers/base/regmap/regcache-lzo.c b/drivers/base/regmap/regcache-lzo.c index 2d53f6f138e1..52ed0d03ce69 100644 --- a/drivers/base/regmap/regcache-lzo.c +++ b/drivers/base/regmap/regcache-lzo.c @@ -332,7 +332,7 @@ out: } static int regcache_lzo_sync(struct regmap *map, unsigned int min, -unsigned int max) +unsigned int max, bool was_reset) { struct regcache_lzo_ctx **lzo_blocks; unsigned int val; diff --git a/drivers/base/regmap/regcache-rbtree.c b/drivers/base/regmap/regcache-rbtree.c index 81751a49d8bf..8fc1727e635c 100644 --- a/drivers/base/regmap/regcache-rbtree.c +++ b/drivers/base/regmap/regcache-rbtree.c @@ -445,7 +445,7 @@ static int regcache_rbtree_write(struct regmap *map, unsigned int reg, } static int regcache_rbtree_sync(struct regmap *map, unsigned int min, - unsigned int max) + unsigned int max, bool was_reset) { struct regcache_rbtree_ctx *rbtree_ctx; struct rb_node *node; @@ -477,7 +477,8 @@ static int regcache_rbtree_sync(struct regmap *map, unsigned int min, ret = regcache_sync_block(map, rbnode-block, rbnode-cache_present, - rbnode-base_reg, start, end); + rbnode-base_reg, start, end, + was_reset); if (ret != 0) return ret; } diff --git a/drivers/base/regmap/regcache.c b/drivers/base/regmap/regcache.c index 7eb7b3b98794..d27b45f50497 100644 --- a/drivers/base/regmap/regcache.c +++ b/drivers/base/regmap/regcache.c @@ -250,7 +250,7 @@ int regcache_write(struct regmap *map, } static int regcache_default_sync(struct regmap *map, unsigned int min, -unsigned int max) +unsigned int max, bool was_reset) { unsigned int reg; @@ -266,10 +266,12 @@ static int regcache_default_sync(struct regmap *map, unsigned int min, if (ret) return ret; - /* Is this the hardware default? If so skip. */ - ret = regcache_lookup_reg(map, reg); - if (ret = 0 val == map-reg_defaults[ret].def
[PATCH V2 4/4] MAINTAINERS: Add entry for tas571x ASoC codec driver
Add self as maintainer for the new driver. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- MAINTAINERS | 6 ++ 1 file changed, 6 insertions(+) diff --git a/MAINTAINERS b/MAINTAINERS index ea0001760035..15153fc37cc4 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -9878,6 +9878,12 @@ L: net...@vger.kernel.org S: Maintained F: drivers/net/ethernet/ti/netcp* +TI TAS571X FAMILY ASoC CODEC DRIVER +M: Kevin Cernekee cerne...@chromium.org +L: alsa-de...@alsa-project.org (moderated for non-subscribers) +S: Odd Fixes +F: sound/soc/codecs/tas571x* + TI TWL4030 SERIES SOC CODEC DRIVER M: Peter Ujfalusi peter.ujfal...@ti.com L: alsa-de...@alsa-project.org (moderated for non-subscribers) -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
[PATCH V2 2/4] ASoC: tas571x: Add DT binding document
Document the bindings for the soon-to-be-added tas571x driver. Signed-off-by: Kevin Cernekee cerne...@chromium.org --- .../devicetree/bindings/sound/tas571x.txt | 41 ++ 1 file changed, 41 insertions(+) create mode 100644 Documentation/devicetree/bindings/sound/tas571x.txt diff --git a/Documentation/devicetree/bindings/sound/tas571x.txt b/Documentation/devicetree/bindings/sound/tas571x.txt new file mode 100644 index ..0ac31d8d5ac4 --- /dev/null +++ b/Documentation/devicetree/bindings/sound/tas571x.txt @@ -0,0 +1,41 @@ +Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers + +The codec is controlled through an I2C interface. It also has two other +signals that can be wired up to GPIOs: reset (strongly recommended), and +powerdown (optional). + +Required properties: + +- compatible: ti,tas5711, ti,tas5717, or ti,tas5719 +- reg: The I2C address of the device +- #sound-dai-cells: must be equal to 0 + +Optional properties: + +- reset-gpios: GPIO specifier for the TAS571x's active low reset line +- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line +- clocks: clock phandle for the MCLK input +- clock-names: should be mclk +- AVDD-supply: regulator phandle for the AVDD supply (all chips) +- DVDD-supply: regulator phandle for the DVDD supply (all chips) +- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719) +- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719) +- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719) +- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711) +- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711) +- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711) +- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711) + +Example: + + tas5717: audio-codec@2a { + compatible = ti,tas5717; + reg = 0x2a; + #sound-dai-cells = 0; + + reset-gpios = gpio5 1 GPIO_ACTIVE_LOW; + pdn-gpios = gpio5 2 GPIO_ACTIVE_LOW; + + clocks = clk_core CLK_I2S; + clock-names = mclk; + }; -- 2.2.0.rc0.207.ga3a616c -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/
Re: [PATCH V2 1/4] regmap: cache: Add was_reset argument to regcache_sync_region()
On Fri, Apr 24, 2015 at 3:36 PM, Kevin Cernekee cerne...@chromium.org wrote: regcache_sync() and regcache_sync_region() currently assume that the hardware has just emerged from a clean reset, and that all registers are in their default states. But that isn't the only possibility; the device may have been in a different state in which the registers were inaccessible but have retained their contents, e.g. clock gating. So we will extend the more versatile of the two functions, regcache_sync_region(), to let the caller decide what assumptions should be made. One driver that can benefit from this is adau1977, which has hacks to overwrite the registers that regcache_sync() might have missed. Also, the powerdown pin on tas571x does not reset the register contents either, so a similar feature will be required by that driver. This commit just adds the new argument by changing the function declarations and call sites, but doesn't wire it up yet. The last two lines of the changelog were inadvertently carried over from an older version of the patch, and should be deleted. Will fix in V3. -- To unsubscribe from this list: send the line unsubscribe linux-kernel in the body of a message to majord...@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/