diff options
author | Bertrand Jacquin <bertrand@jacquin.bzh> | 2019-07-13 13:33:59 +0100 |
---|---|---|
committer | Bertrand Jacquin <bertrand@jacquin.bzh> | 2019-07-13 13:33:59 +0100 |
commit | 0266c0d7aff7015e7b34fcf6293de4736f6bde61 (patch) | |
tree | 159c10c52e9a30ee13ee1ea6a82b8d8690139540 | |
parent | sys-kernel/longterm-sources: Bump 4.19 (diff) | |
download | etc-portage-patches-0266c0d7aff7015e7b34fcf6293de4736f6bde61.tar.gz |
sys-kernel/stable-sources: Drop 5.0
338 files changed, 0 insertions, 331648 deletions
diff --git a/sys-kernel/boest-v5.0.21/0001-patch-4.20-ja1.diff.patch b/sys-kernel/boest-v5.0.21/0001-patch-4.20-ja1.diff.patch deleted file mode 100644 index b86a71a4..00000000 --- a/sys-kernel/boest-v5.0.21/0001-patch-4.20-ja1.diff.patch +++ /dev/null @@ -1,2120 +0,0 @@ -From 1b898047dcc0c19b5a57c3fca0f5ee6eaf9564c0 Mon Sep 17 00:00:00 2001 -From: Julian Anastasov <ja@ssi.bg> -Date: Sun, 20 Jan 2019 13:22:45 +0000 -Subject: [PATCH 01/12] patch-4.20-ja1.diff - -Jumbo patch containing the following parts: - - routes-2.X.*.diff (static_routes, alt_routes, nf_reroute but without arp_prefsrc functionality, it is replaced by arprules and rp_filter_mask) - - hidden-2.X.*.diff (conf/*/hidden) - - arprules-2.X.*.diff (iparp/arprules support) - - rp_filter_mask-2.X.*.diff (conf/*/rp_filter_mask) - - forward_shared-2.X.*.diff (conf/*/forward_shared) - - send-to-self-2.X.*.diff (conf/*/loop, included March 3, 2004, up to Linux 3.5) - -URL: http://ja.ssi.bg/patch-4.20-ja1.diff ---- - Documentation/networking/ip-sysctl.txt | 30 + - include/linux/inetdevice.h | 3 + - include/net/flow.h | 2 + - include/net/ip_fib.h | 5 +- - include/net/netfilter/nf_nat.h | 5 + - include/net/route.h | 5 + - include/uapi/linux/ip.h | 3 + - include/uapi/linux/rtnetlink.h | 64 +- - net/bridge/br_netfilter_hooks.c | 3 + - net/ipv4/arp.c | 695 +++++++++++++++++++- - net/ipv4/devinet.c | 14 +- - net/ipv4/fib_frontend.c | 56 +- - net/ipv4/fib_rules.c | 5 + - net/ipv4/fib_semantics.c | 257 ++++++-- - net/ipv4/fib_trie.c | 3 + - net/ipv4/netfilter/iptable_nat.c | 7 + - net/ipv4/netfilter/nf_nat_masquerade_ipv4.c | 27 +- - net/ipv4/route.c | 69 +- - net/netfilter/nf_nat_core.c | 43 ++ - security/selinux/nlmsgtab.c | 5 +- - 20 files changed, 1173 insertions(+), 128 deletions(-) - -diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt -index e2142fe40cda..2c9787017dae 100644 ---- a/Documentation/networking/ip-sysctl.txt -+++ b/Documentation/networking/ip-sysctl.txt -@@ -1077,6 +1077,19 @@ forwarding - BOOLEAN - Enable IP forwarding on this interface. This controls whether packets - received _on_ this interface can be forwarded. - -+forward_shared - BOOLEAN -+ Integer value determines if a source validation should allow -+ forwarding of packets with local source address. 1 means yes, -+ 0 means no. By default the flag is disabled and such packets -+ are not forwarded. -+ -+ If you enable this flag on internal network, the router will forward -+ packets from internal hosts with shared IP addresses no matter how -+ the rp_filter is set. This flag is activated only if it is -+ enabled both in specific device section and in "all" section. -+ -+ The forward_shared value could be ignored when rp_filter is set to 0. -+ - mc_forwarding - BOOLEAN - Do multicast routing. The kernel needs to be compiled with CONFIG_MROUTE - and a multicast routing daemon is required. -@@ -1192,6 +1205,15 @@ rp_filter - INTEGER - Default value is 0. Note that some distributions enable it - in startup scripts. - -+rp_filter_mask - INTEGER -+ Integer value representing bitmask of the mediums for which the -+ reverse path protection is disabled. If the source validation -+ results in reverse path to interface with medium_id value in -+ the 1..31 range the access is allowed if the corresponding bit -+ is set in the bitmask. The bitmask value is considered only when -+ rp_filter is enabled. By default the bitmask is empty preserving -+ the original rp_filter semantic. -+ - arp_filter - BOOLEAN - 1 - Allows you to have multiple network interfaces on the same - subnet, and have the ARPs for each interface be answered -@@ -1332,6 +1354,14 @@ drop_gratuitous_arp - BOOLEAN - Default: off (0) - - -+hidden - BOOLEAN -+ Hide addresses attached to this device from other devices. -+ Such addresses will never be selected by source address autoselection -+ mechanism, host does not answer broadcast ARP requests for them, -+ does not announce them as source address of ARP requests, but they -+ are still reachable via IP. This flag is activated only if it is -+ enabled both in specific device section and in "all" section. -+ - tag - INTEGER - Allows you to write a number, which can be used as required. - Default value is 0. -diff --git a/include/linux/inetdevice.h b/include/linux/inetdevice.h -index a64f21a97369..f2103b9e67de 100644 ---- a/include/linux/inetdevice.h -+++ b/include/linux/inetdevice.h -@@ -97,9 +97,11 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) - #define IN_DEV_MFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), MC_FORWARDING) - #define IN_DEV_BFORWARD(in_dev) IN_DEV_ANDCONF((in_dev), BC_FORWARDING) - #define IN_DEV_RPFILTER(in_dev) IN_DEV_MAXCONF((in_dev), RP_FILTER) -+#define IN_DEV_RPFILTER_MASK(in_dev) IN_DEV_CONF_GET(in_dev, RP_FILTER_MASK) - #define IN_DEV_SRC_VMARK(in_dev) IN_DEV_ORCONF((in_dev), SRC_VMARK) - #define IN_DEV_SOURCE_ROUTE(in_dev) IN_DEV_ANDCONF((in_dev), \ - ACCEPT_SOURCE_ROUTE) -+#define IN_DEV_FORWARD_SHARED(in_dev) IN_DEV_ANDCONF((in_dev), FORWARD_SHARED) - #define IN_DEV_ACCEPT_LOCAL(in_dev) IN_DEV_ORCONF((in_dev), ACCEPT_LOCAL) - #define IN_DEV_BOOTP_RELAY(in_dev) IN_DEV_ANDCONF((in_dev), BOOTP_RELAY) - -@@ -112,6 +114,7 @@ static inline void ipv4_devconf_setall(struct in_device *in_dev) - SECURE_REDIRECTS) - #define IN_DEV_IDTAG(in_dev) IN_DEV_CONF_GET(in_dev, TAG) - #define IN_DEV_MEDIUM_ID(in_dev) IN_DEV_CONF_GET(in_dev, MEDIUM_ID) -+#define IN_DEV_HIDDEN(in_dev) IN_DEV_ANDCONF((in_dev), HIDDEN) - #define IN_DEV_PROMOTE_SECONDARIES(in_dev) \ - IN_DEV_ORCONF((in_dev), \ - PROMOTE_SECONDARIES) -diff --git a/include/net/flow.h b/include/net/flow.h -index 93f2c9a0f098..b0516bb8b64a 100644 ---- a/include/net/flow.h -+++ b/include/net/flow.h -@@ -91,6 +91,7 @@ struct flowi4 { - #define fl4_ipsec_spi uli.spi - #define fl4_mh_type uli.mht.type - #define fl4_gre_key uli.gre_key -+ __be32 fl4_gw; - } __attribute__((__aligned__(BITS_PER_LONG/8))); - - static inline void flowi4_init_output(struct flowi4 *fl4, int oif, -@@ -114,6 +115,7 @@ static inline void flowi4_init_output(struct flowi4 *fl4, int oif, - fl4->saddr = saddr; - fl4->fl4_dport = dport; - fl4->fl4_sport = sport; -+ fl4->fl4_gw = 0; - } - - /* Reset some input parameters after previous lookup */ -diff --git a/include/net/ip_fib.h b/include/net/ip_fib.h -index 9c8214d2116d..a1b2aa38264b 100644 ---- a/include/net/ip_fib.h -+++ b/include/net/ip_fib.h -@@ -378,6 +378,8 @@ static inline bool fib4_rules_early_flow_dissect(struct net *net, - return true; - } - -+u32 fib_result_table(struct fib_result *res); -+ - #endif /* CONFIG_IP_MULTIPLE_TABLES */ - - /* Exported by fib_frontend.c */ -@@ -387,7 +389,8 @@ __be32 fib_compute_spec_dst(struct sk_buff *skb); - bool fib_info_nh_uses_dev(struct fib_info *fi, const struct net_device *dev); - int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - u8 tos, int oif, struct net_device *dev, -- struct in_device *idev, u32 *itag); -+ struct in_device *idev, u32 *itag, int our); -+void fib_select_default(const struct flowi4 *flp, struct fib_result *res); - #ifdef CONFIG_IP_ROUTE_CLASSID - static inline int fib_num_tclassid_users(struct net *net) - { -diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h -index a17eb2f8d40e..749d505486d3 100644 ---- a/include/net/netfilter/nf_nat.h -+++ b/include/net/netfilter/nf_nat.h -@@ -37,6 +37,11 @@ struct nf_conn_nat { - #endif - }; - -+/* Call input routing for SNAT-ed traffic */ -+unsigned int ip_nat_route_input(void *priv, -+ struct sk_buff *skb, -+ const struct nf_hook_state *state); -+ - /* Set up the info structure to map into this range. */ - unsigned int nf_nat_setup_info(struct nf_conn *ct, - const struct nf_nat_range2 *range, -diff --git a/include/net/route.h b/include/net/route.h -index 9883dc82f723..a617bc7e0d8f 100644 ---- a/include/net/route.h -+++ b/include/net/route.h -@@ -182,6 +182,9 @@ int ip_route_input_noref(struct sk_buff *skb, __be32 dst, __be32 src, - int ip_route_input_rcu(struct sk_buff *skb, __be32 dst, __be32 src, - u8 tos, struct net_device *devin, - struct fib_result *res); -+int ip_route_input_common_rcu(struct sk_buff *skb, __be32 dst, __be32 src, -+ u8 tos, struct net_device *devin, __be32 lsrc, -+ struct fib_result *res); - - static inline int ip_route_input(struct sk_buff *skb, __be32 dst, __be32 src, - u8 tos, struct net_device *devin) -@@ -217,6 +220,8 @@ unsigned int inet_addr_type_dev_table(struct net *net, - void ip_rt_multicast_event(struct in_device *); - int ip_rt_ioctl(struct net *, unsigned int cmd, struct rtentry *rt); - void ip_rt_get_source(u8 *src, struct sk_buff *skb, struct rtable *rt); -+int ip_route_input_lookup(struct sk_buff*, __be32 dst, __be32 src, u8 tos, -+ struct net_device *devin, __be32 lsrc); - struct rtable *rt_dst_alloc(struct net_device *dev, - unsigned int flags, u16 type, - bool nopolicy, bool noxfrm, bool will_cache); -diff --git a/include/uapi/linux/ip.h b/include/uapi/linux/ip.h -index e42d13b55cf3..d03711046f2e 100644 ---- a/include/uapi/linux/ip.h -+++ b/include/uapi/linux/ip.h -@@ -169,6 +169,9 @@ enum - IPV4_DEVCONF_DROP_UNICAST_IN_L2_MULTICAST, - IPV4_DEVCONF_DROP_GRATUITOUS_ARP, - IPV4_DEVCONF_BC_FORWARDING, -+ IPV4_DEVCONF_HIDDEN, -+ IPV4_DEVCONF_RP_FILTER_MASK, -+ IPV4_DEVCONF_FORWARD_SHARED, - __IPV4_DEVCONF_MAX - }; - -diff --git a/include/uapi/linux/rtnetlink.h b/include/uapi/linux/rtnetlink.h -index 46399367627f..92593fd1a055 100644 ---- a/include/uapi/linux/rtnetlink.h -+++ b/include/uapi/linux/rtnetlink.h -@@ -157,6 +157,13 @@ enum { - RTM_GETCHAIN, - #define RTM_GETCHAIN RTM_GETCHAIN - -+ RTM_NEWARPRULE = 104, -+#define RTM_NEWARPRULE RTM_NEWARPRULE -+ RTM_DELARPRULE, -+#define RTM_DELARPRULE RTM_DELARPRULE -+ RTM_GETARPRULE, -+#define RTM_GETARPRULE RTM_GETARPRULE -+ - __RTM_MAX, - #define RTM_MAX (((__RTM_MAX + 3) & ~3) - 1) - }; -@@ -374,8 +381,11 @@ struct rtnexthop { - #define RTNH_F_OFFLOAD 8 /* offloaded route */ - #define RTNH_F_LINKDOWN 16 /* carrier-down on nexthop */ - #define RTNH_F_UNRESOLVED 32 /* The entry is unresolved (ipmr) */ -+#define RTNH_F_SUSPECT 64 /* We don't know the real state */ -+#define RTNH_F_BADSTATE (RTNH_F_DEAD | RTNH_F_SUSPECT) - --#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | RTNH_F_OFFLOAD) -+#define RTNH_COMPARE_MASK (RTNH_F_DEAD | RTNH_F_LINKDOWN | \ -+ RTNH_F_OFFLOAD | RTNH_F_SUSPECT) - - /* Macros to handle hexthops */ - -@@ -617,6 +627,54 @@ enum { - - #define NDUSEROPT_MAX (__NDUSEROPT_MAX - 1) - -+/****************************************************************************** -+ * Definitions used in ARP tables administration -+ ****/ -+ -+#define ARPA_TABLE_INPUT 0 -+#define ARPA_TABLE_OUTPUT 1 -+#define ARPA_TABLE_FORWARD 2 -+#define ARPA_TABLE_ALL -1 -+ -+#define ARPM_F_PREFSRC 0x0001 -+#define ARPM_F_WILDIIF 0x0002 -+#define ARPM_F_WILDOIF 0x0004 -+#define ARPM_F_BROADCAST 0x0008 -+#define ARPM_F_UNICAST 0x0010 -+ -+struct arpmsg -+{ -+ unsigned char arpm_family; -+ unsigned char arpm_table; -+ unsigned char arpm_action; -+ unsigned char arpm_from_len; -+ unsigned char arpm_to_len; -+ unsigned char arpm__pad1; -+ unsigned short arpm__pad2; -+ unsigned arpm_pref; -+ unsigned arpm_flags; -+}; -+ -+enum -+{ -+ ARPA_UNSPEC, -+ ARPA_FROM, /* FROM IP prefix */ -+ ARPA_TO, /* TO IP prefix */ -+ ARPA_LLFROM, /* FROM LL prefix */ -+ ARPA_LLTO, /* TO LL prefix */ -+ ARPA_LLSRC, /* New SRC lladdr */ -+ ARPA_LLDST, /* New DST lladdr */ -+ ARPA_IIF, /* In interface prefix */ -+ ARPA_OIF, /* Out interface prefix */ -+ ARPA_SRC, /* New IP SRC */ -+ ARPA_DST, /* New IP DST, not used */ -+ ARPA_PACKETS, /* Packets */ -+}; -+ -+#define ARPA_MAX ARPA_PACKETS -+ -+#define ARPA_RTA(r) ((struct rtattr*)(((char*)(r)) + NLMSG_ALIGN(sizeof(struct arpmsg)))) -+ - #ifndef __KERNEL__ - /* RTnetlink multicast groups - backwards compatibility for userspace */ - #define RTMGRP_LINK 1 -@@ -637,6 +695,8 @@ enum { - #define RTMGRP_DECnet_IFADDR 0x1000 - #define RTMGRP_DECnet_ROUTE 0x4000 - -+#define RTMGRP_ARP 0x00010000 -+ - #define RTMGRP_IPV6_PREFIX 0x20000 - #endif - -@@ -704,6 +764,8 @@ enum rtnetlink_groups { - #define RTNLGRP_IPV4_MROUTE_R RTNLGRP_IPV4_MROUTE_R - RTNLGRP_IPV6_MROUTE_R, - #define RTNLGRP_IPV6_MROUTE_R RTNLGRP_IPV6_MROUTE_R -+ RTNLGRP_ARP, -+#define RTNLGRP_ARP RTNLGRP_ARP - __RTNLGRP_MAX - }; - #define RTNLGRP_MAX (__RTNLGRP_MAX - 1) -diff --git a/net/bridge/br_netfilter_hooks.c b/net/bridge/br_netfilter_hooks.c -index fc605758323b..5f2ba880d0ed 100644 ---- a/net/bridge/br_netfilter_hooks.c -+++ b/net/bridge/br_netfilter_hooks.c -@@ -347,6 +347,9 @@ static int br_nf_pre_routing_finish(struct net *net, struct sock *sk, struct sk_ - - nf_bridge->frag_max_size = IPCB(skb)->frag_max_size; - -+ /* Old skb->dst is not expected, it is lost in all cases */ -+ skb_dst_drop(skb); -+ - if (nf_bridge->pkt_otherhost) { - skb->pkt_type = PACKET_OTHERHOST; - nf_bridge->pkt_otherhost = false; -diff --git a/net/ipv4/arp.c b/net/ipv4/arp.c -index 850a6f13a082..bf0bf575eff6 100644 ---- a/net/ipv4/arp.c -+++ b/net/ipv4/arp.c -@@ -71,6 +71,9 @@ - * sending (e.g. insert 8021q tag). - * Harald Welte : convert to make use of jenkins hash - * Jesper D. Brouer: Proxy ARP PVLAN RFC 3069 support. -+ * Julian Anastasov: "hidden" flag: hide the -+ * interface and don't reply for it -+ * Julian Anastasov: ARP filtering via netlink - */ - - #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt -@@ -95,6 +98,7 @@ - #include <linux/proc_fs.h> - #include <linux/seq_file.h> - #include <linux/stat.h> -+#include <net/netlink.h> - #include <linux/init.h> - #include <linux/net.h> - #include <linux/rcupdate.h> -@@ -185,6 +189,48 @@ struct neigh_table arp_tbl = { - }; - EXPORT_SYMBOL(arp_tbl); - -+struct arpf_node { -+ struct arpf_node * at_next; -+ u32 at_pref; -+ u32 at_from; -+ u32 at_from_mask; -+ u32 at_to; -+ u32 at_to_mask; -+ u32 at_src; -+ atomic_t at_packets; -+ atomic_t at_refcnt; -+ unsigned at_flags; -+ unsigned char at_from_len; -+ unsigned char at_to_len; -+ unsigned char at_action; -+ char at_dead; -+ unsigned char at_llfrom_len; -+ unsigned char at_llto_len; -+ unsigned char at_llsrc_len; -+ unsigned char at_lldst_len; -+ unsigned char at_iif_len; -+ unsigned char at_oif_len; -+ unsigned short at__pad1; -+ unsigned char at_llfrom[MAX_ADDR_LEN]; -+ unsigned char at_llto[MAX_ADDR_LEN]; -+ unsigned char at_llsrc[MAX_ADDR_LEN]; -+ unsigned char at_lldst[MAX_ADDR_LEN]; -+ char at_iif[IFNAMSIZ]; -+ char at_oif[IFNAMSIZ]; -+}; -+ -+static struct arpf_node *arp_tabs[3]; -+ -+static struct kmem_cache *arpf_cachep; -+ -+static DEFINE_RWLOCK(arpf_lock); -+ -+static void -+arpf_send(int table, struct net *net, struct sk_buff *skb, u32 sip, u32 tip, -+ unsigned char *from_hw, unsigned char *to_hw, -+ struct net_device *idev, struct net_device *odev, -+ struct dst_entry *dst); -+ - int arp_mc_map(__be32 addr, u8 *haddr, struct net_device *dev, int dir) - { - switch (dev->type) { -@@ -338,7 +384,9 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) - struct net_device *dev = neigh->dev; - __be32 target = *(__be32 *)neigh->primary_key; - int probes = atomic_read(&neigh->probes); -- struct in_device *in_dev; -+ struct in_device *in_dev, *in_dev2; -+ struct net_device *dev2; -+ int mode; - struct dst_entry *dst = NULL; - - rcu_read_lock(); -@@ -347,9 +395,22 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) - rcu_read_unlock(); - return; - } -- switch (IN_DEV_ARP_ANNOUNCE(in_dev)) { -+ mode = IN_DEV_ARP_ANNOUNCE(in_dev); -+ if (mode != 2 && skb && -+ (dev2 = __ip_dev_find(dev_net(dev), ip_hdr(skb)->saddr, -+ false)) != NULL && -+ (saddr = ip_hdr(skb)->saddr, -+ in_dev2 = __in_dev_get_rcu(dev2)) != NULL && -+ IN_DEV_HIDDEN(in_dev2)) { -+ saddr = 0; -+ goto get; -+ } -+ -+ switch (mode) { - default: - case 0: /* By default announce any local IP */ -+ if (saddr) -+ break; - if (skb && inet_addr_type_dev_table(dev_net(dev), dev, - ip_hdr(skb)->saddr) == RTN_LOCAL) - saddr = ip_hdr(skb)->saddr; -@@ -357,9 +418,10 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) - case 1: /* Restrict announcements of saddr in same subnet */ - if (!skb) - break; -- saddr = ip_hdr(skb)->saddr; -- if (inet_addr_type_dev_table(dev_net(dev), dev, -- saddr) == RTN_LOCAL) { -+ if (saddr || -+ (saddr = ip_hdr(skb)->saddr, -+ inet_addr_type_dev_table(dev_net(dev), dev, -+ saddr) == RTN_LOCAL)) { - /* saddr should be known to target */ - if (inet_addr_onlink(in_dev, target, saddr)) - break; -@@ -369,6 +431,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) - case 2: /* Avoid secondary IPs, get a primary/preferred one */ - break; - } -+ -+get: - rcu_read_unlock(); - - if (!saddr) -@@ -390,8 +454,8 @@ static void arp_solicit(struct neighbour *neigh, struct sk_buff *skb) - - if (skb && !(dev->priv_flags & IFF_XMIT_DST_RELEASE)) - dst = skb_dst(skb); -- arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, target, dev, saddr, -- dst_hw, dev->dev_addr, NULL, dst); -+ arpf_send(ARPA_TABLE_OUTPUT, dev_net(dev), skb, saddr, target, NULL, -+ dst_hw, NULL, dev, dst); - } - - static int arp_ignore(struct in_device *in_dev, __be32 sip, __be32 tip) -@@ -448,6 +512,21 @@ static int arp_filter(__be32 sip, __be32 tip, struct net_device *dev) - return flag; - } - -+static int arp_hidden(u32 tip, struct net_device *dev) -+{ -+ struct net_device *dev2; -+ struct in_device *in_dev2; -+ int ret = 0; -+ -+ if (!IPV4_DEVCONF_ALL(dev_net(dev), HIDDEN)) -+ return 0; -+ -+ if ((dev2 = __ip_dev_find(dev_net(dev), tip, false)) && dev2 != dev && -+ (in_dev2 = __in_dev_get_rcu(dev2)) && IN_DEV_HIDDEN(in_dev2)) -+ ret = 1; -+ return ret; -+} -+ - /* - * Check if we can use proxy ARP for this path - */ -@@ -808,9 +887,10 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) - if (sip == 0) { - if (arp->ar_op == htons(ARPOP_REQUEST) && - inet_addr_type_dev_table(net, dev, tip) == RTN_LOCAL && -+ !arp_hidden(tip, dev) && - !arp_ignore(in_dev, sip, tip)) -- arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, dev, tip, -- sha, dev->dev_addr, sha, reply_dst); -+ arpf_send(ARPA_TABLE_INPUT, net, skb, sip, tip, sha, -+ tha, dev, NULL, reply_dst); - goto out_consume_skb; - } - -@@ -826,13 +906,14 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) - dont_send = arp_ignore(in_dev, sip, tip); - if (!dont_send && IN_DEV_ARPFILTER(in_dev)) - dont_send = arp_filter(sip, tip, dev); -+ if (!dont_send && skb->pkt_type != PACKET_HOST) -+ dont_send = arp_hidden(tip,dev); - if (!dont_send) { - n = neigh_event_ns(&arp_tbl, sha, &sip, dev); - if (n) { -- arp_send_dst(ARPOP_REPLY, ETH_P_ARP, -- sip, dev, tip, sha, -- dev->dev_addr, sha, -- reply_dst); -+ arpf_send(ARPA_TABLE_INPUT, net, skb, -+ sip, tip, sha, tha, dev, -+ NULL, reply_dst); - neigh_release(n); - } - } -@@ -850,10 +931,9 @@ static int arp_process(struct net *net, struct sock *sk, struct sk_buff *skb) - if (NEIGH_CB(skb)->flags & LOCALLY_ENQUEUED || - skb->pkt_type == PACKET_HOST || - NEIGH_VAR(in_dev->arp_parms, PROXY_DELAY) == 0) { -- arp_send_dst(ARPOP_REPLY, ETH_P_ARP, -- sip, dev, tip, sha, -- dev->dev_addr, sha, -- reply_dst); -+ arpf_send(ARPA_TABLE_FORWARD, net, -+ skb, sip, tip, sha, tha, dev, -+ rt->dst.dev, reply_dst); - } else { - pneigh_enqueue(&arp_tbl, - in_dev->arp_parms, skb); -@@ -1279,6 +1359,577 @@ void arp_ifdown(struct net_device *dev) - } - - -+static void arpf_destroy(struct arpf_node *afp) -+{ -+ if (!afp->at_dead) { -+ printk(KERN_ERR "Destroying alive arp table node %p from %08lx\n", afp, -+ *(((unsigned long*)&afp)-1)); -+ return; -+ } -+ kmem_cache_free(arpf_cachep, afp); -+} -+ -+static inline void arpf_put(struct arpf_node *afp) -+{ -+ if (atomic_dec_and_test(&afp->at_refcnt)) -+ arpf_destroy(afp); -+} -+ -+static inline struct arpf_node * -+arpf_lookup(int table, struct sk_buff *skb, u32 sip, u32 tip, -+ unsigned char *from_hw, unsigned char *to_hw, -+ struct net_device *idev, struct net_device *odev) -+{ -+ int sz_iif = idev? strlen(idev->name) : 0; -+ int sz_oif = odev? strlen(odev->name) : 0; -+ int alen; -+ struct arpf_node *afp; -+ -+ if (ARPA_TABLE_OUTPUT != table) { -+ alen = idev->addr_len; -+ } else { -+ if (!from_hw) from_hw = odev->dev_addr; -+ if (!to_hw) to_hw = odev->broadcast; -+ alen = odev->addr_len; -+ } -+ -+ read_lock_bh(&arpf_lock); -+ for (afp = arp_tabs[table]; afp; afp = afp->at_next) { -+ if ((tip ^ afp->at_to) & afp->at_to_mask) -+ continue; -+ if ((sip ^ afp->at_from) & afp->at_from_mask) -+ continue; -+ if (afp->at_llfrom_len && -+ (afp->at_llfrom_len > alen || -+ memcmp(from_hw, afp->at_llfrom, afp->at_llfrom_len))) -+ continue; -+ if (afp->at_llto_len && -+ (afp->at_llto_len > alen || -+ memcmp(to_hw, afp->at_llto, afp->at_llto_len))) -+ continue; -+ if (afp->at_iif_len && -+ (afp->at_iif_len > sz_iif || -+ memcmp(afp->at_iif, idev->name, afp->at_iif_len) || -+ (sz_iif != afp->at_iif_len && -+ !(afp->at_flags & ARPM_F_WILDIIF)))) -+ continue; -+ if (afp->at_oif_len && -+ (afp->at_oif_len > sz_oif || -+ memcmp(afp->at_oif, odev->name, afp->at_oif_len) || -+ (sz_oif != afp->at_oif_len && -+ !(afp->at_flags & ARPM_F_WILDOIF)))) -+ continue; -+ if (afp->at_flags & ARPM_F_BROADCAST && -+ skb->pkt_type == PACKET_HOST) -+ continue; -+ if (afp->at_flags & ARPM_F_UNICAST && -+ skb->pkt_type != PACKET_HOST) -+ continue; -+ if (afp->at_llsrc_len && afp->at_llsrc_len != alen) -+ continue; -+ if (afp->at_lldst_len && afp->at_lldst_len != alen) -+ continue; -+ atomic_inc(&afp->at_refcnt); -+ atomic_inc(&afp->at_packets); -+ break; -+ } -+ read_unlock_bh(&arpf_lock); -+ return afp; -+} -+ -+static void -+arpf_send(int table, struct net *net, struct sk_buff *skb, u32 sip, u32 tip, -+ unsigned char *from_hw, unsigned char *to_hw, -+ struct net_device *idev, struct net_device *odev, -+ struct dst_entry *dst) -+{ -+ struct arpf_node *afp = NULL; -+ -+ if (!arp_tabs[table] || -+ !net_eq(net, &init_net) || -+ !(afp = arpf_lookup(table, skb, sip, tip, -+ from_hw, to_hw, idev, odev))) { -+ switch (table) { -+ case ARPA_TABLE_INPUT: -+ case ARPA_TABLE_FORWARD: -+ arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, idev, tip, -+ from_hw, idev->dev_addr, from_hw, dst); -+ break; -+ case ARPA_TABLE_OUTPUT: -+ arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, tip, odev, sip, -+ to_hw, odev->dev_addr, NULL, dst); -+ break; -+ } -+ return; -+ } -+ -+ /* deny? */ -+ if (!afp->at_action) goto out; -+ -+ switch (table) { -+ case ARPA_TABLE_INPUT: -+ case ARPA_TABLE_FORWARD: -+ arp_send_dst(ARPOP_REPLY, ETH_P_ARP, sip, idev, tip, -+ afp->at_lldst_len?afp->at_lldst:from_hw, -+ afp->at_llsrc_len?afp->at_llsrc:idev->dev_addr, -+ afp->at_lldst_len?afp->at_lldst:from_hw, dst); -+ break; -+ case ARPA_TABLE_OUTPUT: -+ if (afp->at_flags & ARPM_F_PREFSRC && afp->at_src == 0) { -+ struct rtable *rt; -+ struct flowi4 fl4 = { .daddr = tip, -+ .flowi4_oif = odev->ifindex }; -+ -+ rt = ip_route_output_key(net, &fl4); -+ if (IS_ERR(rt)) -+ break; -+ sip = fl4.saddr; -+ ip_rt_put(rt); -+ if (!sip) -+ break; -+ } -+ arp_send_dst(ARPOP_REQUEST, ETH_P_ARP, tip, odev, -+ afp->at_src?:sip, -+ afp->at_lldst_len?afp->at_lldst:to_hw, -+ afp->at_llsrc_len?afp->at_llsrc:odev->dev_addr, -+ NULL, dst); -+ break; -+ } -+ -+out: -+ arpf_put(afp); -+} -+ -+static int -+arpf_fill_node(struct sk_buff *skb, u32 portid, u32 seq, unsigned flags, -+ int event, int table, struct arpf_node *afp) -+{ -+ struct arpmsg *am; -+ struct nlmsghdr *nlh; -+ u32 packets = atomic_read(&afp->at_packets); -+ -+ nlh = nlmsg_put(skb, portid, seq, event, sizeof(*am), 0); -+ if (nlh == NULL) -+ return -ENOBUFS; -+ nlh->nlmsg_flags = flags; -+ am = nlmsg_data(nlh); -+ am->arpm_family = AF_UNSPEC; -+ am->arpm_table = table; -+ am->arpm_action = afp->at_action; -+ am->arpm_from_len = afp->at_from_len; -+ am->arpm_to_len = afp->at_to_len; -+ am->arpm_pref = afp->at_pref; -+ am->arpm_flags = afp->at_flags; -+ if (afp->at_from_len && -+ nla_put(skb, ARPA_FROM, 4, &afp->at_from)) -+ goto nla_put_failure; -+ if (afp->at_to_len && -+ nla_put(skb, ARPA_TO, 4, &afp->at_to)) -+ goto nla_put_failure; -+ if ((afp->at_src || afp->at_flags & ARPM_F_PREFSRC) && -+ nla_put(skb, ARPA_SRC, 4, &afp->at_src)) -+ goto nla_put_failure; -+ if (afp->at_iif[0] && -+ nla_put(skb, ARPA_IIF, sizeof(afp->at_iif), afp->at_iif)) -+ goto nla_put_failure; -+ if (afp->at_oif[0] && -+ nla_put(skb, ARPA_OIF, sizeof(afp->at_oif), afp->at_oif)) -+ goto nla_put_failure; -+ if (afp->at_llfrom_len && -+ nla_put(skb, ARPA_LLFROM, afp->at_llfrom_len, afp->at_llfrom)) -+ goto nla_put_failure; -+ if (afp->at_llto_len && -+ nla_put(skb, ARPA_LLTO, afp->at_llto_len, afp->at_llto)) -+ goto nla_put_failure; -+ if (afp->at_llsrc_len && -+ nla_put(skb, ARPA_LLSRC, afp->at_llsrc_len, afp->at_llsrc)) -+ goto nla_put_failure; -+ if (afp->at_lldst_len && -+ nla_put(skb, ARPA_LLDST, afp->at_lldst_len, afp->at_lldst)) -+ goto nla_put_failure; -+ if (nla_put(skb, ARPA_PACKETS, 4, &packets)) -+ goto nla_put_failure; -+ nlmsg_end(skb, nlh); -+ return 0; -+ -+nla_put_failure: -+ nlmsg_cancel(skb, nlh); -+ return -EMSGSIZE; -+} -+ -+static void -+arpmsg_notify(struct sk_buff *oskb, struct nlmsghdr *nlh, int table, -+ struct arpf_node *afp, int event) -+{ -+ struct sk_buff *skb; -+ u32 portid = oskb ? NETLINK_CB(oskb).portid : 0; -+ int payload = sizeof(struct arpmsg) + 256; -+ int err = -ENOBUFS; -+ -+ skb = nlmsg_new(nlmsg_total_size(payload), GFP_KERNEL); -+ if (!skb) -+ goto errout; -+ -+ err = arpf_fill_node(skb, portid, nlh->nlmsg_seq, 0, event, table, afp); -+ if (err < 0) { -+ kfree_skb(skb); -+ goto errout; -+ } -+ -+ rtnl_notify(skb, &init_net, portid, RTNLGRP_ARP, nlh, GFP_KERNEL); -+ return; -+errout: -+ if (err < 0) -+ rtnl_set_sk_err(&init_net, RTNLGRP_ARP, err); -+} -+ -+static inline int -+arpf_str_size(int a, struct nlattr **rta, int maxlen) -+{ -+ int size = 0; -+ -+ if (rta[a] && (size = nla_len(rta[a]))) { -+ if (size > maxlen) -+ size = maxlen; -+ } -+ return size; -+} -+ -+static inline int -+arpf_get_str(int a, struct nlattr **rta, unsigned char *p, -+ int maxlen, unsigned char *l) -+{ -+ int size = arpf_str_size(a, rta, maxlen); -+ -+ if (size) { -+ memcpy(p, nla_data(rta[a]), size); -+ *l = size; -+ } -+ return size; -+} -+ -+#define ARPF_MATCH_U32(ind, field) ( \ -+ (!rta[ind] && r->at_ ## field == 0) || \ -+ (rta[ind] && \ -+ *(u32*) nla_data(rta[ind]) == r->at_ ## field)) -+ -+#define ARPF_MATCH_STR(ind, field) ( \ -+ (!rta[ind] && r->at_ ## field ## _len == 0) || \ -+ (rta[ind] && r->at_ ## field ## _len && \ -+ r->at_ ## field ## _len < nla_len(rta[ind]) && \ -+ strcmp(nla_data(rta[ind]), r->at_ ## field) == 0)) -+ -+#define ARPF_MATCH_DATA(ind, field) ( \ -+ (!rta[ind] && r->at_ ## field ## _len == 0) || \ -+ (rta[ind] && r->at_ ## field ## _len && \ -+ r->at_ ## field ## _len == nla_len(rta[ind]) && \ -+ memcmp(nla_data(rta[ind]), &r->at_ ## field, \ -+ r->at_ ## field ## _len) == 0)) -+ -+/* RTM_NEWARPRULE/RTM_DELARPRULE/RTM_GETARPRULE */ -+ -+int arpf_rule_ctl(struct sk_buff *skb, struct nlmsghdr *n, -+ struct netlink_ext_ack *extack) -+{ -+ struct net *net = sock_net(skb->sk); -+ struct nlattr *rta[ARPA_MAX + 1]; -+ struct arpmsg *am; -+ struct arpf_node *r, **rp, **prevp = 0, **delp = 0, *newp = 0; -+ unsigned pref = 1; -+ int size, ret; -+ -+ if (!capable(CAP_NET_ADMIN)) -+ return -EPERM; -+ -+ if (!net_eq(net, &init_net)) -+ return -EINVAL; -+ -+ ret = nlmsg_parse(n, sizeof(struct arpmsg), rta, ARPA_MAX, NULL, -+ extack); -+ if (ret < 0) -+ return ret; -+ -+ am = nlmsg_data(n); -+ ret = -EINVAL; -+ if (am->arpm_table >= sizeof(arp_tabs)/sizeof(arp_tabs[0])) -+ goto out; -+ if (!((~am->arpm_flags) & (ARPM_F_BROADCAST|ARPM_F_UNICAST))) -+ goto out; -+ if (am->arpm_action > 1) -+ goto out; -+ if (am->arpm_to_len > 32 || am->arpm_from_len > 32) -+ goto out; -+ if (am->arpm_flags & ARPM_F_WILDIIF && -+ (!rta[ARPA_IIF] || !nla_len(rta[ARPA_IIF]) || -+ !*(char*) nla_data(rta[ARPA_IIF]))) -+ am->arpm_flags &= ~ARPM_F_WILDIIF; -+ if (am->arpm_flags & ARPM_F_WILDOIF && -+ (!rta[ARPA_OIF] || !nla_len(rta[ARPA_OIF]) || -+ !*(char*) nla_data(rta[ARPA_OIF]))) -+ am->arpm_flags &= ~ARPM_F_WILDOIF; -+ switch (am->arpm_table) { -+ case ARPA_TABLE_INPUT: -+ if (rta[ARPA_SRC] || rta[ARPA_OIF]) -+ goto out; -+ break; -+ case ARPA_TABLE_OUTPUT: -+ if (rta[ARPA_IIF]) -+ goto out; -+ if (am->arpm_flags & (ARPM_F_BROADCAST|ARPM_F_UNICAST)) -+ goto out; -+ break; -+ case ARPA_TABLE_FORWARD: -+ if (rta[ARPA_SRC]) -+ goto out; -+ break; -+ } -+ if (rta[ARPA_SRC] && !*(u32*) nla_data(rta[ARPA_SRC])) -+ am->arpm_flags |= ARPM_F_PREFSRC; -+ else -+ am->arpm_flags &= ~ARPM_F_PREFSRC; -+ -+ for (rp = &arp_tabs[am->arpm_table]; (r=*rp) != NULL; rp=&r->at_next) { -+ if (pref < r->at_pref) -+ prevp = rp; -+ if (am->arpm_pref == r->at_pref || -+ (!am->arpm_pref && -+ am->arpm_to_len == r->at_to_len && -+ am->arpm_from_len == r->at_from_len && -+ !((am->arpm_flags ^ r->at_flags) & -+ (ARPM_F_BROADCAST | ARPM_F_UNICAST | -+ ARPM_F_WILDIIF | ARPM_F_WILDOIF)) && -+ ARPF_MATCH_U32(ARPA_TO, to) && -+ ARPF_MATCH_U32(ARPA_FROM, from) && -+ ARPF_MATCH_DATA(ARPA_LLFROM, llfrom) && -+ ARPF_MATCH_DATA(ARPA_LLTO, llto) && -+ ARPF_MATCH_STR(ARPA_IIF, iif) && -+ ARPF_MATCH_STR(ARPA_OIF, oif) && -+ (n->nlmsg_type != RTM_DELARPRULE || -+ /* DEL matches more keys */ -+ (am->arpm_flags == r->at_flags && -+ am->arpm_action == r->at_action && -+ ARPF_MATCH_U32(ARPA_SRC, src) && -+ ARPF_MATCH_DATA(ARPA_LLSRC, llsrc) && -+ ARPF_MATCH_DATA(ARPA_LLDST, lldst) -+ ) -+ ) -+ ) -+ ) -+ break; -+ if (am->arpm_pref && r->at_pref > am->arpm_pref) { -+ r = NULL; -+ break; -+ } -+ pref = r->at_pref+1; -+ } -+ -+ /* -+ * r=NULL: *rp != NULL (stopped before next pref), pref: not valid -+ * *rp == NULL (not found), pref: ready to use -+ * r!=NULL: found, pref: not valid -+ * -+ * prevp=NULL: no free slot -+ * prevp!=NULL: free slot for rule -+ */ -+ -+ if (n->nlmsg_type == RTM_DELARPRULE) { -+ if (!r) -+ return -ESRCH; -+ delp = rp; -+ goto dequeue; -+ } -+ -+ if (r) { -+ /* Existing rule */ -+ ret = -EEXIST; -+ if (n->nlmsg_flags&NLM_F_EXCL) -+ goto out; -+ -+ if (n->nlmsg_flags&NLM_F_REPLACE) { -+ pref = r->at_pref; -+ prevp = delp = rp; -+ goto replace; -+ } -+ } -+ -+ if (n->nlmsg_flags&NLM_F_APPEND) { -+ if (r) { -+ pref = r->at_pref+1; -+ for (rp=&r->at_next; (r=*rp) != NULL; rp=&r->at_next) { -+ if (pref != r->at_pref) -+ break; -+ pref ++; -+ } -+ ret = -EBUSY; -+ if (!pref) -+ goto out; -+ } else if (am->arpm_pref) -+ pref = am->arpm_pref; -+ prevp = rp; -+ } -+ -+ if (!(n->nlmsg_flags&NLM_F_CREATE)) { -+ ret = -ENOENT; -+ if (n->nlmsg_flags&NLM_F_EXCL || r) -+ ret = 0; -+ goto out; -+ } -+ -+ if (!(n->nlmsg_flags&NLM_F_APPEND)) { -+ if (!prevp) { -+ ret = -EBUSY; -+ if (r || *rp || -+ (!am->arpm_pref && arp_tabs[am->arpm_table])) -+ goto out; -+ prevp = rp; -+ pref = am->arpm_pref? : 99; -+ } else { -+ if (r || !am->arpm_pref) { -+ pref = (*prevp)->at_pref - 1; -+ if (am->arpm_pref && am->arpm_pref < pref) -+ pref = am->arpm_pref; -+ } else { -+ prevp = rp; -+ pref = am->arpm_pref; -+ } -+ } -+ } -+ -+replace: -+ -+ ret = -ENOMEM; -+ r = kmem_cache_alloc(arpf_cachep, GFP_KERNEL); -+ if (!r) -+ return ret; -+ memset(r, 0, sizeof(*r)); -+ -+ arpf_get_str(ARPA_LLFROM, rta, r->at_llfrom, MAX_ADDR_LEN, -+ &r->at_llfrom_len); -+ arpf_get_str(ARPA_LLTO, rta, r->at_llto, MAX_ADDR_LEN, -+ &r->at_llto_len); -+ arpf_get_str(ARPA_LLSRC, rta, r->at_llsrc, MAX_ADDR_LEN, -+ &r->at_llsrc_len); -+ arpf_get_str(ARPA_LLDST, rta, r->at_lldst, MAX_ADDR_LEN, -+ &r->at_lldst_len); -+ -+ if (delp) -+ r->at_next = (*delp)->at_next; -+ else if (*prevp) -+ r->at_next = *prevp; -+ -+ r->at_pref = pref; -+ r->at_from_len = am->arpm_from_len; -+ r->at_from_mask = inet_make_mask(r->at_from_len); -+ if (rta[ARPA_FROM]) -+ r->at_from = *(u32*) nla_data(rta[ARPA_FROM]); -+ r->at_from &= r->at_from_mask; -+ r->at_to_len = am->arpm_to_len; -+ r->at_to_mask = inet_make_mask(r->at_to_len); -+ if (rta[ARPA_TO]) -+ r->at_to = *(u32*) nla_data(rta[ARPA_TO]); -+ r->at_to &= r->at_to_mask; -+ if (rta[ARPA_SRC]) -+ r->at_src = *(u32*) nla_data(rta[ARPA_SRC]); -+ if (rta[ARPA_PACKETS]) { -+ u32 packets = *(u32*) nla_data(rta[ARPA_PACKETS]); -+ atomic_set(&r->at_packets, packets); -+ } -+ atomic_set(&r->at_refcnt, 1); -+ r->at_flags = am->arpm_flags; -+ r->at_action = am->arpm_action; -+ -+ if (rta[ARPA_IIF] && (size = nla_len(rta[ARPA_IIF]))) { -+ if (size >= sizeof(r->at_iif)) -+ size = sizeof(r->at_iif)-1; -+ memcpy(r->at_iif, nla_data(rta[ARPA_IIF]), size); -+ r->at_iif_len = strlen(r->at_iif); -+ } -+ if (rta[ARPA_OIF] && (size = nla_len(rta[ARPA_OIF]))) { -+ if (size >= sizeof(r->at_oif)) -+ size = sizeof(r->at_oif)-1; -+ memcpy(r->at_oif, nla_data(rta[ARPA_OIF]), size); -+ r->at_oif_len = strlen(r->at_oif); -+ } -+ -+ newp = r; -+ -+dequeue: -+ -+ if (delp) { -+ r = *delp; -+ write_lock_bh(&arpf_lock); -+ if (newp) { -+ if (!rta[ARPA_PACKETS]) -+ atomic_set(&newp->at_packets, -+ atomic_read(&r->at_packets)); -+ *delp = newp; -+ } else { -+ *delp = r->at_next; -+ } -+ r->at_dead = 1; -+ write_unlock_bh(&arpf_lock); -+ arpmsg_notify(skb, n, am->arpm_table, r, RTM_DELARPRULE); -+ arpf_put(r); -+ prevp = 0; -+ } -+ -+ if (newp) { -+ if (prevp) { -+ write_lock_bh(&arpf_lock); -+ *prevp = newp; -+ write_unlock_bh(&arpf_lock); -+ } -+ arpmsg_notify(skb, n, am->arpm_table, newp, RTM_NEWARPRULE); -+ } -+ -+ ret = 0; -+ -+out: -+ return ret; -+} -+ -+int arpf_dump_table(int t, struct sk_buff *skb, struct netlink_callback *cb) -+{ -+ int idx, ret = -1; -+ struct arpf_node *afp; -+ int s_idx = cb->args[1]; -+ -+ for (idx=0, afp = arp_tabs[t]; afp; afp = afp->at_next, idx++) { -+ if (idx < s_idx) -+ continue; -+ if (arpf_fill_node(skb, NETLINK_CB(cb->skb).portid, -+ cb->nlh->nlmsg_seq, NLM_F_MULTI, RTM_NEWARPRULE, t, afp) < 0) -+ goto out; -+ } -+ -+ ret = skb->len; -+ -+out: -+ cb->args[1] = idx; -+ -+ return ret; -+} -+ -+int arpf_dump_rules(struct sk_buff *skb, struct netlink_callback *cb) -+{ -+ int idx; -+ int s_idx = cb->args[0]; -+ -+ read_lock_bh(&arpf_lock); -+ for (idx = 0; idx < sizeof(arp_tabs)/sizeof(arp_tabs[0]); idx++) { -+ if (idx < s_idx) -+ continue; -+ if (idx > s_idx) -+ memset(&cb->args[1], 0, sizeof(cb->args)-1*sizeof(cb->args[0])); -+ if (arpf_dump_table(idx, skb, cb) < 0) -+ break; -+ } -+ read_unlock_bh(&arpf_lock); -+ cb->args[0] = idx; -+ -+ return skb->len; -+} -+ - /* - * Called once on startup. - */ -@@ -1292,6 +1943,16 @@ static int arp_proc_init(void); - - void __init arp_init(void) - { -+ arpf_cachep = kmem_cache_create("ip_arpf_cache", -+ sizeof(struct arpf_node), 0, -+ SLAB_HWCACHE_ALIGN, NULL); -+ if (!arpf_cachep) -+ panic("IP: failed to allocate ip_arpf_cache\n"); -+ -+ rtnl_register(PF_UNSPEC, RTM_NEWARPRULE, arpf_rule_ctl, NULL, 0); -+ rtnl_register(PF_UNSPEC, RTM_DELARPRULE, arpf_rule_ctl, NULL, 0); -+ rtnl_register(PF_UNSPEC, RTM_GETARPRULE, NULL, arpf_dump_rules, 0); -+ - neigh_table_init(NEIGH_ARP_TABLE, &arp_tbl); - - dev_add_pack(&arp_packet_type); -diff --git a/net/ipv4/devinet.c b/net/ipv4/devinet.c -index e258a00b4a3d..e9e24f6fb16c 100644 ---- a/net/ipv4/devinet.c -+++ b/net/ipv4/devinet.c -@@ -1308,9 +1308,14 @@ __be32 inet_select_addr(const struct net_device *dev, __be32 dst, int scope) - if (!in_dev) - continue; - -- addr = in_dev_select_addr(in_dev, scope); -- if (addr) -- goto out_unlock; -+ for_primary_ifa(in_dev) { -+ if (!IN_DEV_HIDDEN(in_dev) && -+ ifa->ifa_scope != RT_SCOPE_LINK && -+ ifa->ifa_scope <= scope) { -+ addr = ifa->ifa_local; -+ goto out_unlock; -+ } -+ } endfor_ifa(in_dev); - } - out_unlock: - rcu_read_unlock(); -@@ -2427,13 +2432,16 @@ static struct devinet_sysctl_table { - DEVINET_SYSCTL_RW_ENTRY(SEND_REDIRECTS, "send_redirects"), - DEVINET_SYSCTL_RW_ENTRY(ACCEPT_SOURCE_ROUTE, - "accept_source_route"), -+ DEVINET_SYSCTL_RW_ENTRY(FORWARD_SHARED, "forward_shared"), - DEVINET_SYSCTL_RW_ENTRY(ACCEPT_LOCAL, "accept_local"), - DEVINET_SYSCTL_RW_ENTRY(SRC_VMARK, "src_valid_mark"), - DEVINET_SYSCTL_RW_ENTRY(PROXY_ARP, "proxy_arp"), - DEVINET_SYSCTL_RW_ENTRY(MEDIUM_ID, "medium_id"), -+ DEVINET_SYSCTL_RW_ENTRY(RP_FILTER_MASK, "rp_filter_mask"), - DEVINET_SYSCTL_RW_ENTRY(BOOTP_RELAY, "bootp_relay"), - DEVINET_SYSCTL_RW_ENTRY(LOG_MARTIANS, "log_martians"), - DEVINET_SYSCTL_RW_ENTRY(TAG, "tag"), -+ DEVINET_SYSCTL_RW_ENTRY(HIDDEN, "hidden"), - DEVINET_SYSCTL_RW_ENTRY(ARPFILTER, "arp_filter"), - DEVINET_SYSCTL_RW_ENTRY(ARP_ANNOUNCE, "arp_announce"), - DEVINET_SYSCTL_RW_ENTRY(ARP_IGNORE, "arp_ignore"), -diff --git a/net/ipv4/fib_frontend.c b/net/ipv4/fib_frontend.c -index ed14ec245584..1c5782a2e983 100644 ---- a/net/ipv4/fib_frontend.c -+++ b/net/ipv4/fib_frontend.c -@@ -51,6 +51,8 @@ - - #ifndef CONFIG_IP_MULTIPLE_TABLES - -+#define FIB_RES_TABLE(r) (RT_TABLE_MAIN) -+ - static int __net_init fib4_rules_init(struct net *net) - { - struct fib_table *local_table, *main_table; -@@ -80,6 +82,8 @@ static bool fib4_has_custom_rules(struct net *net) - } - #else - -+#define FIB_RES_TABLE(r) (fib_result_table(r)) -+ - struct fib_table *fib_new_table(struct net *net, u32 id) - { - struct fib_table *tb, *alias = NULL; -@@ -351,13 +355,19 @@ EXPORT_SYMBOL_GPL(fib_info_nh_uses_dev); - */ - static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - u8 tos, int oif, struct net_device *dev, -- int rpf, struct in_device *idev, u32 *itag) -+ int rpf, struct in_device *idev, u32 *itag, -+ int our) - { - struct net *net = dev_net(dev); - struct flow_keys flkeys; -+ u32 table; -+ unsigned char prefixlen; -+ unsigned char scope; - int ret, no_addr; - struct fib_result res; - struct flowi4 fl4; -+ int fwdsh; -+ unsigned int rpf_mask; - bool dev_match; - - fl4.flowi4_oif = 0; -@@ -371,10 +381,13 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - fl4.flowi4_tun_key.tun_id = 0; - fl4.flowi4_flags = 0; - fl4.flowi4_uid = sock_net_uid(net, NULL); -+ fl4.fl4_gw = 0; - - no_addr = idev->ifa_list == NULL; - -+ fwdsh = IN_DEV_FORWARD_SHARED(idev); - fl4.flowi4_mark = IN_DEV_SRC_VMARK(idev) ? skb->mark : 0; -+ rpf_mask = IN_DEV_RPFILTER_MASK(idev); - if (!fib4_rules_early_flow_dissect(net, skb, &fl4, &flkeys)) { - fl4.flowi4_proto = 0; - fl4.fl4_sport = 0; -@@ -383,7 +396,12 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - - if (fib_lookup(net, &fl4, &res, 0)) - goto last_resort; -- if (res.type != RTN_UNICAST && -+ if (fwdsh) { -+ fwdsh = (res.type == RTN_LOCAL && !our); -+ if (fwdsh) -+ rpf = 0; -+ } -+ if (res.type != RTN_UNICAST && !fwdsh && - (res.type != RTN_LOCAL || !IN_DEV_ACCEPT_LOCAL(idev))) - goto e_inval; - fib_combine_itag(itag, &res); -@@ -393,17 +411,36 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; - return ret; - } -+ if (rpf_mask && rpf) { -+ int omi = 0; -+ -+ idev = __in_dev_get_rcu(FIB_RES_DEV(res)); -+ if (idev) -+ omi = IN_DEV_MEDIUM_ID(idev); -+ if (omi >= 1 && omi <= 31 && ((1 << omi) & rpf_mask)) -+ rpf = 0; -+ } - if (no_addr) - goto last_resort; -- if (rpf == 1) -- goto e_rpf; -+ table = FIB_RES_TABLE(&res); -+ prefixlen = res.prefixlen; -+ scope = res.scope; - fl4.flowi4_oif = dev->ifindex; -+ if (fwdsh) -+ fl4.flowi4_iif = LOOPBACK_IFINDEX; - - ret = 0; - if (fib_lookup(net, &fl4, &res, FIB_LOOKUP_IGNORE_LINKSTATE) == 0) { -- if (res.type == RTN_UNICAST) -+ if (res.type == RTN_UNICAST && -+ ((table == FIB_RES_TABLE(&res) && -+ res.prefixlen >= prefixlen && res.scope >= scope) || -+ !rpf)) { - ret = FIB_RES_NH(res).nh_scope >= RT_SCOPE_HOST; -+ return ret; -+ } - } -+ if (rpf == 1) -+ goto e_rpf; - return ret; - - last_resort: -@@ -421,7 +458,7 @@ static int __fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - /* Ignore rp_filter for packets protected by IPsec. */ - int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - u8 tos, int oif, struct net_device *dev, -- struct in_device *idev, u32 *itag) -+ struct in_device *idev, u32 *itag, int our) - { - int r = secpath_exists(skb) ? 0 : IN_DEV_RPFILTER(idev); - struct net *net = dev_net(dev); -@@ -446,7 +483,8 @@ int fib_validate_source(struct sk_buff *skb, __be32 src, __be32 dst, - } - - full_check: -- return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev, itag); -+ return __fib_validate_source(skb, src, dst, tos, oif, dev, r, idev, -+ itag, our); - } - - static inline __be32 sk_extract_addr(struct sockaddr *addr) -@@ -1328,9 +1366,7 @@ static int fib_inetaddr_event(struct notifier_block *this, unsigned long event, - switch (event) { - case NETDEV_UP: - fib_add_ifaddr(ifa); --#ifdef CONFIG_IP_ROUTE_MULTIPATH - fib_sync_up(dev, RTNH_F_DEAD); --#endif - atomic_inc(&net->ipv4.dev_addr_genid); - rt_cache_flush(dev_net(dev)); - break; -@@ -1374,9 +1410,7 @@ static int fib_netdev_event(struct notifier_block *this, unsigned long event, vo - for_ifa(in_dev) { - fib_add_ifaddr(ifa); - } endfor_ifa(in_dev); --#ifdef CONFIG_IP_ROUTE_MULTIPATH - fib_sync_up(dev, RTNH_F_DEAD); --#endif - atomic_inc(&net->ipv4.dev_addr_genid); - rt_cache_flush(net); - break; -diff --git a/net/ipv4/fib_rules.c b/net/ipv4/fib_rules.c -index cfec3af54c8d..6ffc52a5c272 100644 ---- a/net/ipv4/fib_rules.c -+++ b/net/ipv4/fib_rules.c -@@ -78,6 +78,11 @@ unsigned int fib4_rules_seq_read(struct net *net) - return fib_rules_seq_read(net, AF_INET); - } - -+u32 fib_result_table(struct fib_result *res) -+{ -+ return res->table ? res->table->tb_id : RT_TABLE_UNSPEC; -+} -+ - int __fib_lookup(struct net *net, struct flowi4 *flp, - struct fib_result *res, unsigned int flags) - { -diff --git a/net/ipv4/fib_semantics.c b/net/ipv4/fib_semantics.c -index 5022bc63863a..d8e8711406c6 100644 ---- a/net/ipv4/fib_semantics.c -+++ b/net/ipv4/fib_semantics.c -@@ -53,6 +53,7 @@ static struct hlist_head *fib_info_hash; - static struct hlist_head *fib_info_laddrhash; - static unsigned int fib_info_hash_size; - static unsigned int fib_info_cnt; -+DEFINE_RWLOCK(fib_nhflags_lock); - - #define DEVINDEX_HASHBITS 8 - #define DEVINDEX_HASHSIZE (1U << DEVINDEX_HASHBITS) -@@ -433,28 +434,71 @@ void rtmsg_fib(int event, __be32 key, struct fib_alias *fa, - - static int fib_detect_death(struct fib_info *fi, int order, - struct fib_info **last_resort, int *last_idx, -- int dflt) -+ int dflt, int *last_nhsel, -+ const struct flowi4 *flp) - { - struct neighbour *n; -- int state = NUD_NONE; -+ int nhsel; -+ int state; -+ struct fib_nh * nh; -+ __be32 dst; -+ int flag, dead = 1; - -- n = neigh_lookup(&arp_tbl, &fi->fib_nh[0].nh_gw, fi->fib_dev); -- if (n) { -- state = n->nud_state; -- neigh_release(n); -- } else { -- return 0; -- } -- if (state == NUD_REACHABLE) -- return 0; -- if ((state & NUD_VALID) && order != dflt) -- return 0; -- if ((state & NUD_VALID) || -- (*last_idx < 0 && order > dflt && state != NUD_INCOMPLETE)) { -- *last_resort = fi; -- *last_idx = order; -+ /* change_nexthops(fi) { */ -+ for (nhsel = 0, nh = fi->fib_nh; nhsel < fi->fib_nhs; nh++, nhsel++) { -+ if (flp->flowi4_oif && flp->flowi4_oif != nh->nh_oif && -+ !(flp->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF)) -+ continue; -+ if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw && nh->nh_gw && -+ nh->nh_scope == RT_SCOPE_LINK) -+ continue; -+ if (nh->nh_flags & RTNH_F_DEAD) -+ continue; -+ -+ flag = 0; -+ if (nh->nh_dev->flags & IFF_NOARP) { -+ dead = 0; -+ goto setfl; -+ } -+ -+ dst = nh->nh_gw; -+ if (!nh->nh_gw || nh->nh_scope != RT_SCOPE_LINK) -+ dst = flp->daddr; -+ -+ state = NUD_NONE; -+ n = neigh_lookup(&arp_tbl, &dst, nh->nh_dev); -+ if (n) { -+ state = n->nud_state; -+ neigh_release(n); -+ } -+ if (state == NUD_REACHABLE || -+ ((state & NUD_VALID) && order != dflt)) { -+ dead = 0; -+ goto setfl; -+ } -+ if (!(state & NUD_VALID)) -+ flag = 1; -+ if (!dead) -+ goto setfl; -+ if ((state & NUD_VALID) || -+ (*last_idx < 0 && order >= dflt)) { -+ *last_resort = fi; -+ *last_idx = order; -+ *last_nhsel = nhsel; -+ } -+ -+ setfl: -+ -+ read_lock_bh(&fib_nhflags_lock); -+ if (flag) -+ nh->nh_flags |= RTNH_F_SUSPECT; -+ else -+ nh->nh_flags &= ~RTNH_F_SUSPECT; -+ read_unlock_bh(&fib_nhflags_lock); - } -- return 1; -+ /* } endfor_nexthops(fi) */ -+ -+ return dead; - } - - #ifdef CONFIG_IP_ROUTE_MULTIPATH -@@ -781,6 +825,7 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, - int err = 0; - struct net *net; - struct net_device *dev; -+ struct fib_info *fi = nh->nh_parent; - - net = cfg->fc_nlinfo.nl_net; - if (nh->nh_gw) { -@@ -800,9 +845,12 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, - return -ENODEV; - } - if (!(dev->flags & IFF_UP)) { -- NL_SET_ERR_MSG(extack, -- "Nexthop device is not up"); -- return -ENETDOWN; -+ if (fi->fib_protocol != RTPROT_STATIC) { -+ NL_SET_ERR_MSG(extack, -+ "Nexthop device is not up"); -+ return -ENETDOWN; -+ } -+ nh->nh_flags |= RTNH_F_DEAD; - } - addr_type = inet_addr_type_dev_table(net, dev, nh->nh_gw); - if (addr_type != RTN_UNICAST) { -@@ -847,31 +895,57 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, - err = fib_lookup(net, &fl4, &res, - FIB_LOOKUP_IGNORE_LINKSTATE); - } -+ } -+ if (err) { -+ struct in_device *in_dev; - -- if (err) { -+ if (err != -ENETUNREACH || -+ fi->fib_protocol != RTPROT_STATIC) { - NL_SET_ERR_MSG(extack, - "Nexthop has invalid gateway"); -- rcu_read_unlock(); -- return err; -+ goto out; - } -+ -+ in_dev = inetdev_by_index(net, nh->nh_oif); -+ if (in_dev == NULL || -+ in_dev->dev->flags & IFF_UP) { -+ NL_SET_ERR_MSG(extack, -+ "Device for nexthop is not up"); -+ goto out; -+ } -+ nh->nh_flags |= RTNH_F_DEAD; -+ nh->nh_scope = RT_SCOPE_LINK; -+ nh->nh_dev = in_dev->dev; -+ dev_hold(nh->nh_dev); -+ } else { -+ err = -EINVAL; -+ if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) { -+ NL_SET_ERR_MSG(extack, -+ "Nexthop has invalid gateway"); -+ goto out; -+ } -+ nh->nh_scope = res.scope; -+ nh->nh_oif = FIB_RES_OIF(res); -+ nh->nh_dev = dev = FIB_RES_DEV(res); -+ if (!dev) { -+ NL_SET_ERR_MSG(extack, -+ "No egress device for nexthop gateway"); -+ goto out; -+ } -+ dev_hold(dev); -+ if (!netif_carrier_ok(dev)) -+ nh->nh_flags |= RTNH_F_LINKDOWN; -+ if (!(nh->nh_dev->flags & IFF_UP)) { -+ if (fi->fib_protocol != RTPROT_STATIC) { -+ err = -ENETDOWN; -+ NL_SET_ERR_MSG(extack, -+ "Device for nexthop is not up"); -+ goto out; -+ } -+ nh->nh_flags |= RTNH_F_DEAD; -+ } -+ err = 0; - } -- err = -EINVAL; -- if (res.type != RTN_UNICAST && res.type != RTN_LOCAL) { -- NL_SET_ERR_MSG(extack, "Nexthop has invalid gateway"); -- goto out; -- } -- nh->nh_scope = res.scope; -- nh->nh_oif = FIB_RES_OIF(res); -- nh->nh_dev = dev = FIB_RES_DEV(res); -- if (!dev) { -- NL_SET_ERR_MSG(extack, -- "No egress device for nexthop gateway"); -- goto out; -- } -- dev_hold(dev); -- if (!netif_carrier_ok(dev)) -- nh->nh_flags |= RTNH_F_LINKDOWN; -- err = (dev->flags & IFF_UP) ? 0 : -ENETDOWN; - } else { - struct in_device *in_dev; - -@@ -887,8 +961,12 @@ static int fib_check_nh(struct fib_config *cfg, struct fib_nh *nh, - goto out; - err = -ENETDOWN; - if (!(in_dev->dev->flags & IFF_UP)) { -- NL_SET_ERR_MSG(extack, "Device for nexthop is not up"); -- goto out; -+ if (fi->fib_protocol != RTPROT_STATIC) { -+ NL_SET_ERR_MSG(extack, -+ "Device for nexthop is not up"); -+ goto out; -+ } -+ nh->nh_flags |= RTNH_F_DEAD; - } - nh->nh_dev = in_dev->dev; - dev_hold(nh->nh_dev); -@@ -1535,10 +1613,15 @@ int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force) - prev_fi = fi; - dead = 0; - change_nexthops(fi) { -- if (nexthop_nh->nh_flags & RTNH_F_DEAD) -- dead++; -- else if (nexthop_nh->nh_dev == dev && -- nexthop_nh->nh_scope != scope) { -+ if (nexthop_nh->nh_flags & RTNH_F_DEAD) { -+ if (fi->fib_protocol != RTPROT_STATIC || -+ nexthop_nh->nh_dev == NULL || -+ __in_dev_get_rtnl(nexthop_nh->nh_dev) == NULL || -+ nexthop_nh->nh_dev->flags&IFF_UP) -+ dead++; -+ } else if (nexthop_nh->nh_dev == dev && -+ nexthop_nh->nh_scope != scope) { -+ write_lock_bh(&fib_nhflags_lock); - switch (event) { - case NETDEV_DOWN: - case NETDEV_UNREGISTER: -@@ -1550,7 +1633,11 @@ int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force) - } - call_fib_nh_notifiers(nexthop_nh, - FIB_EVENT_NH_DEL); -- dead++; -+ write_unlock_bh(&fib_nhflags_lock); -+ if (fi->fib_protocol != RTPROT_STATIC || -+ force || -+ __in_dev_get_rtnl(dev) == NULL) -+ dead++; - } - #ifdef CONFIG_IP_ROUTE_MULTIPATH - if (event == NETDEV_UNREGISTER && -@@ -1580,13 +1667,13 @@ int fib_sync_down_dev(struct net_device *dev, unsigned long event, bool force) - } - - /* Must be invoked inside of an RCU protected region. */ --static void fib_select_default(const struct flowi4 *flp, struct fib_result *res) -+void fib_select_default(const struct flowi4 *flp, struct fib_result *res) - { - struct fib_info *fi = NULL, *last_resort = NULL; - struct hlist_head *fa_head = res->fa_head; - struct fib_table *tb = res->table; - u8 slen = 32 - res->prefixlen; -- int order = -1, last_idx = -1; -+ int order = -1, last_idx = -1, last_nhsel = 0; - struct fib_alias *fa, *fa1 = NULL; - u32 last_prio = res->fi->fib_priority; - u8 last_tos = 0; -@@ -1614,9 +1701,6 @@ static void fib_select_default(const struct flowi4 *flp, struct fib_result *res) - if (next_fi->fib_scope != res->scope || - fa->fa_type != RTN_UNICAST) - continue; -- if (!next_fi->fib_nh[0].nh_gw || -- next_fi->fib_nh[0].nh_scope != RT_SCOPE_LINK) -- continue; - - fib_alias_accessed(fa); - -@@ -1625,7 +1709,8 @@ static void fib_select_default(const struct flowi4 *flp, struct fib_result *res) - break; - fa1 = fa; - } else if (!fib_detect_death(fi, order, &last_resort, -- &last_idx, fa1->fa_default)) { -+ &last_idx, fa1->fa_default, -+ &last_nhsel, flp)) { - fib_result_assign(res, fi); - fa1->fa_default = order; - goto out; -@@ -1635,28 +1720,39 @@ static void fib_select_default(const struct flowi4 *flp, struct fib_result *res) - } - - if (order <= 0 || !fi) { -+ if (fi && fi->fib_nhs > 1 && -+ fib_detect_death(fi, order, &last_resort, &last_idx, -+ fa1->fa_default, &last_nhsel, flp) && -+ last_resort == fi) { -+ read_lock_bh(&fib_nhflags_lock); -+ fi->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT; -+ read_unlock_bh(&fib_nhflags_lock); -+ } - if (fa1) - fa1->fa_default = -1; - goto out; - } - - if (!fib_detect_death(fi, order, &last_resort, &last_idx, -- fa1->fa_default)) { -+ fa1->fa_default, &last_nhsel, flp)) { - fib_result_assign(res, fi); - fa1->fa_default = order; - goto out; - } - -- if (last_idx >= 0) -+ if (last_idx >= 0) { - fib_result_assign(res, last_resort); -+ read_lock_bh(&fib_nhflags_lock); -+ last_resort->fib_nh[last_nhsel].nh_flags &= ~RTNH_F_SUSPECT; -+ read_unlock_bh(&fib_nhflags_lock); -+ } - fa1->fa_default = last_idx; - out: - return; - } - - /* -- * Dead device goes up. We wake up dead nexthops. -- * It takes sense only on multipath routes. -+ * Dead device goes up or new address is added. We wake up dead nexthops. - */ - int fib_sync_up(struct net_device *dev, unsigned int nh_flags) - { -@@ -1664,8 +1760,10 @@ int fib_sync_up(struct net_device *dev, unsigned int nh_flags) - unsigned int hash; - struct hlist_head *head; - struct fib_nh *nh; -- int ret; -+ struct fib_result res; -+ int ret, rep; - -+repeat: - if (!(dev->flags & IFF_UP)) - return 0; - -@@ -1680,6 +1778,7 @@ int fib_sync_up(struct net_device *dev, unsigned int nh_flags) - hash = fib_devindex_hashfn(dev->ifindex); - head = &fib_info_devhash[hash]; - ret = 0; -+ rep = 0; - - hlist_for_each_entry(nh, head, nh_hash) { - struct fib_info *fi = nh->nh_parent; -@@ -1692,16 +1791,37 @@ int fib_sync_up(struct net_device *dev, unsigned int nh_flags) - prev_fi = fi; - alive = 0; - change_nexthops(fi) { -- if (!(nexthop_nh->nh_flags & nh_flags)) { -- alive++; -+ if (!(nexthop_nh->nh_flags & nh_flags)) - continue; -- } - if (!nexthop_nh->nh_dev || - !(nexthop_nh->nh_dev->flags & IFF_UP)) - continue; - if (nexthop_nh->nh_dev != dev || - !__in_dev_get_rtnl(dev)) - continue; -+ if ((nh_flags & RTNH_F_DEAD) && nexthop_nh->nh_gw && -+ fi->fib_protocol == RTPROT_STATIC) { -+ struct flowi4 fl4 = { -+ .daddr = nexthop_nh->nh_gw, -+ .flowi4_scope = nexthop_nh->nh_scope, -+ .flowi4_oif = nexthop_nh->nh_oif, -+ }; -+ -+ rcu_read_lock(); -+ if (fib_lookup(dev_net(dev), &fl4, &res, -+ FIB_LOOKUP_IGNORE_LINKSTATE) != 0) { -+ rcu_read_unlock(); -+ continue; -+ } -+ if (res.type != RTN_UNICAST && -+ res.type != RTN_LOCAL) { -+ rcu_read_unlock(); -+ continue; -+ } -+ nexthop_nh->nh_scope = res.scope; -+ rcu_read_unlock(); -+ rep = 1; -+ } - alive++; - nexthop_nh->nh_flags &= ~nh_flags; - call_fib_nh_notifiers(nexthop_nh, FIB_EVENT_NH_ADD); -@@ -1714,6 +1834,8 @@ int fib_sync_up(struct net_device *dev, unsigned int nh_flags) - - fib_rebalance(fi); - } -+ if (rep) -+ goto repeat; - - return ret; - } -@@ -1767,23 +1889,16 @@ void fib_select_multipath(struct fib_result *res, int hash) - void fib_select_path(struct net *net, struct fib_result *res, - struct flowi4 *fl4, const struct sk_buff *skb) - { -- if (fl4->flowi4_oif && !(fl4->flowi4_flags & FLOWI_FLAG_SKIP_NH_OIF)) -- goto check_saddr; -- -+ if (res->type == RTN_UNICAST) -+ fib_select_default(fl4, res); - #ifdef CONFIG_IP_ROUTE_MULTIPATH - if (res->fi->fib_nhs > 1) { - int h = fib_multipath_hash(net, fl4, skb, NULL); - - fib_select_multipath(res, h); - } -- else - #endif -- if (!res->prefixlen && -- res->table->tb_num_default > 1 && -- res->type == RTN_UNICAST) -- fib_select_default(fl4, res); - --check_saddr: - if (!fl4->saddr) - fl4->saddr = FIB_RES_PREFSRC(net, *res); - } -diff --git a/net/ipv4/fib_trie.c b/net/ipv4/fib_trie.c -index a573e37e0615..d7572cbcfd7c 100644 ---- a/net/ipv4/fib_trie.c -+++ b/net/ipv4/fib_trie.c -@@ -1482,6 +1482,9 @@ int fib_table_lookup(struct fib_table *tb, const struct flowi4 *flp, - if (flp->flowi4_oif && - flp->flowi4_oif != nh->nh_oif) - continue; -+ if (flp->fl4_gw && flp->fl4_gw != nh->nh_gw && -+ nh->nh_gw && nh->nh_scope == RT_SCOPE_LINK) -+ continue; - } - - if (!(fib_flags & FIB_LOOKUP_NOREF)) -diff --git a/net/ipv4/netfilter/iptable_nat.c b/net/ipv4/netfilter/iptable_nat.c -index a317445448bf..9be4af94f10e 100644 ---- a/net/ipv4/netfilter/iptable_nat.c -+++ b/net/ipv4/netfilter/iptable_nat.c -@@ -45,6 +45,13 @@ static const struct nf_hook_ops nf_nat_ipv4_ops[] = { - .hooknum = NF_INET_PRE_ROUTING, - .priority = NF_IP_PRI_NAT_DST, - }, -+ /* Before routing, route before mangling */ -+ { -+ .hook = ip_nat_route_input, -+ .pf = NFPROTO_IPV4, -+ .hooknum = NF_INET_PRE_ROUTING, -+ .priority = NF_IP_PRI_LAST-1, -+ }, - { - .hook = iptable_nat_do_chain, - .pf = NFPROTO_IPV4, -diff --git a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c -index 41327bb99093..96a6daa525e5 100644 ---- a/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c -+++ b/net/ipv4/netfilter/nf_nat_masquerade_ipv4.c -@@ -30,8 +30,8 @@ nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum, - struct nf_conn_nat *nat; - enum ip_conntrack_info ctinfo; - struct nf_nat_range2 newrange; -- const struct rtable *rt; -- __be32 newsrc, nh; -+ struct rtable *rt; -+ __be32 newsrc; - - WARN_ON(hooknum != NF_INET_POST_ROUTING); - -@@ -46,12 +46,23 @@ nf_nat_masquerade_ipv4(struct sk_buff *skb, unsigned int hooknum, - if (ct->tuplehash[IP_CT_DIR_ORIGINAL].tuple.src.u3.ip == 0) - return NF_ACCEPT; - -- rt = skb_rtable(skb); -- nh = rt_nexthop(rt, ip_hdr(skb)->daddr); -- newsrc = inet_select_addr(out, nh, RT_SCOPE_UNIVERSE); -- if (!newsrc) { -- pr_info("%s ate my IP address\n", out->name); -- return NF_DROP; -+ { -+ struct flowi4 fl4 = { .flowi4_tos = RT_TOS(ip_hdr(skb)->tos), -+ .flowi4_mark = skb->mark, -+ .flowi4_oif = out->ifindex, -+ .daddr = ip_hdr(skb)->daddr, -+ .fl4_gw = skb_rtable(skb)->rt_gateway }; -+ rt = ip_route_output_key(dev_net(out), &fl4); -+ if (IS_ERR(rt)) { -+ /* Funky routing can do this. */ -+ if (net_ratelimit()) -+ pr_info("%s:" -+ " No route: Rusty's brain broke!\n", -+ out->name); -+ return NF_DROP; -+ } -+ newsrc = fl4.saddr; -+ ip_rt_put(rt); - } - - nat = nf_ct_nat_ext_add(ct); -diff --git a/net/ipv4/route.c b/net/ipv4/route.c -index b66f78fad98c..d9aed502cd75 100644 ---- a/net/ipv4/route.c -+++ b/net/ipv4/route.c -@@ -1649,7 +1649,7 @@ int ip_mc_validate_source(struct sk_buff *skb, __be32 daddr, __be32 saddr, - return -EINVAL; - } else { - err = fib_validate_source(skb, saddr, 0, tos, 0, dev, -- in_dev, itag); -+ in_dev, itag, 1); - if (err < 0) - return err; - } -@@ -1724,7 +1724,7 @@ static void ip_handle_martian_source(struct net_device *dev, - static int __mkroute_input(struct sk_buff *skb, - const struct fib_result *res, - struct in_device *in_dev, -- __be32 daddr, __be32 saddr, u32 tos) -+ __be32 daddr, __be32 saddr, u32 tos, __be32 lsrc) - { - struct fib_nh_exception *fnhe; - struct rtable *rth; -@@ -1741,7 +1741,7 @@ static int __mkroute_input(struct sk_buff *skb, - } - - err = fib_validate_source(skb, saddr, daddr, tos, FIB_RES_OIF(*res), -- in_dev->dev, in_dev, &itag); -+ in_dev->dev, in_dev, &itag, 0); - if (err < 0) { - ip_handle_martian_source(in_dev->dev, in_dev, skb, daddr, - saddr); -@@ -1751,7 +1751,7 @@ static int __mkroute_input(struct sk_buff *skb, - - do_cache = res->fi && !itag; - if (out_dev == in_dev && err && IN_DEV_TX_REDIRECTS(out_dev) && -- skb->protocol == htons(ETH_P_IP) && -+ skb->protocol == htons(ETH_P_IP) && !lsrc && - (IN_DEV_SHARED_MEDIA(out_dev) || - inet_addr_onlink(out_dev, saddr, FIB_RES_GW(*res)))) - IPCB(skb)->flags |= IPSKB_DOREDIRECT; -@@ -1909,10 +1909,12 @@ int fib_multipath_hash(const struct net *net, const struct flowi4 *fl4, - - static int ip_mkroute_input(struct sk_buff *skb, - struct fib_result *res, -+ const struct flowi4 *fl4, - struct in_device *in_dev, - __be32 daddr, __be32 saddr, u32 tos, -- struct flow_keys *hkeys) -+ struct flow_keys *hkeys, __be32 lsrc) - { -+ fib_select_default(fl4, res); - #ifdef CONFIG_IP_ROUTE_MULTIPATH - if (res->fi && res->fi->fib_nhs > 1) { - int h = fib_multipath_hash(res->fi->fib_net, NULL, skb, hkeys); -@@ -1922,7 +1924,7 @@ static int ip_mkroute_input(struct sk_buff *skb, - #endif - - /* create a routing cache entry */ -- return __mkroute_input(skb, res, in_dev, daddr, saddr, tos); -+ return __mkroute_input(skb, res, in_dev, daddr, saddr, tos, lsrc); - } - - /* -@@ -1937,7 +1939,7 @@ static int ip_mkroute_input(struct sk_buff *skb, - */ - - static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, -- u8 tos, struct net_device *dev, -+ u8 tos, struct net_device *dev, __be32 lsrc, - struct fib_result *res) - { - struct in_device *in_dev = __in_dev_get_rcu(dev); -@@ -1995,18 +1997,25 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, - goto martian_source; - } - -+ if (lsrc) { -+ if (ipv4_is_multicast(lsrc) || ipv4_is_lbcast(lsrc) || -+ ipv4_is_zeronet(lsrc) || ipv4_is_loopback(lsrc)) -+ goto martian_source; -+ } -+ - /* - * Now we are ready to route packet. - */ - fl4.flowi4_oif = 0; -- fl4.flowi4_iif = dev->ifindex; -+ fl4.flowi4_iif = lsrc ? LOOPBACK_IFINDEX : dev->ifindex; - fl4.flowi4_mark = skb->mark; - fl4.flowi4_tos = tos; - fl4.flowi4_scope = RT_SCOPE_UNIVERSE; - fl4.flowi4_flags = 0; - fl4.daddr = daddr; -- fl4.saddr = saddr; -+ fl4.saddr = lsrc? : saddr; - fl4.flowi4_uid = sock_net_uid(net, NULL); -+ fl4.fl4_gw = 0; - - if (fib4_rules_early_flow_dissect(net, skb, &fl4, &_flkeys)) { - flkeys = &_flkeys; -@@ -2017,6 +2026,8 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, - } - - err = fib_lookup(net, &fl4, res, 0); -+ fl4.flowi4_iif = dev->ifindex; -+ fl4.saddr = saddr; - if (err != 0) { - if (!IN_DEV_FORWARD(in_dev)) - err = -EHOSTUNREACH; -@@ -2031,7 +2042,7 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, - - if (res->type == RTN_LOCAL) { - err = fib_validate_source(skb, saddr, daddr, tos, -- 0, dev, in_dev, &itag); -+ 0, dev, in_dev, &itag, 1); - if (err < 0) - goto martian_source; - goto local_input; -@@ -2045,16 +2056,19 @@ static int ip_route_input_slow(struct sk_buff *skb, __be32 daddr, __be32 saddr, - goto martian_destination; - - make_route: -- err = ip_mkroute_input(skb, res, in_dev, daddr, saddr, tos, flkeys); -+ err = ip_mkroute_input(skb, res, &fl4, in_dev, daddr, saddr, tos, -+ flkeys, lsrc); - out: return err; - - brd_input: - if (skb->protocol != htons(ETH_P_IP)) - goto e_inval; -+ if (lsrc) -+ goto e_inval; - - if (!ipv4_is_zeronet(saddr)) { - err = fib_validate_source(skb, saddr, 0, tos, 0, dev, -- in_dev, &itag); -+ in_dev, &itag, 1); - if (err < 0) - goto martian_source; - } -@@ -2158,9 +2172,26 @@ int ip_route_input_noref(struct sk_buff *skb, __be32 daddr, __be32 saddr, - } - EXPORT_SYMBOL(ip_route_input_noref); - -+int ip_route_input_lookup(struct sk_buff *skb, __be32 daddr, __be32 saddr, -+ u8 tos, struct net_device *dev, __be32 lsrc) -+{ -+ struct fib_result res; -+ int err; -+ -+ tos &= IPTOS_RT_MASK; -+ rcu_read_lock(); -+ err = ip_route_input_common_rcu(skb, daddr, saddr, tos, dev, lsrc, -+ &res); -+ rcu_read_unlock(); -+ -+ return err; -+} -+EXPORT_SYMBOL(ip_route_input_lookup); -+ - /* called with rcu_read_lock held */ --int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr, -- u8 tos, struct net_device *dev, struct fib_result *res) -+int ip_route_input_common_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr, -+ u8 tos, struct net_device *dev, __be32 lsrc, -+ struct fib_result *res) - { - /* Multicast recognition logic is moved from route cache to here. - The problem was that too many Ethernet cards have broken/missing -@@ -2206,7 +2237,13 @@ int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr, - return err; - } - -- return ip_route_input_slow(skb, daddr, saddr, tos, dev, res); -+ return ip_route_input_slow(skb, daddr, saddr, tos, dev, lsrc, res); -+} -+ -+int ip_route_input_rcu(struct sk_buff *skb, __be32 daddr, __be32 saddr, -+ u8 tos, struct net_device *dev, struct fib_result *res) -+{ -+ return ip_route_input_common_rcu(skb, daddr, saddr, tos, dev, 0, res); - } - - /* called with rcu_read_lock() */ -@@ -2458,6 +2495,7 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4, - fl4->daddr = fl4->saddr = htonl(INADDR_LOOPBACK); - dev_out = net->loopback_dev; - fl4->flowi4_oif = LOOPBACK_IFINDEX; -+ fl4->fl4_gw = 0; - res->type = RTN_LOCAL; - flags |= RTCF_LOCAL; - goto make_route; -@@ -2516,6 +2554,7 @@ struct rtable *ip_route_output_key_hash_rcu(struct net *net, struct flowi4 *fl4, - orig_oif = FIB_RES_OIF(*res); - - fl4->flowi4_oif = dev_out->ifindex; -+ fl4->fl4_gw = 0; - flags |= RTCF_LOCAL; - goto make_route; - } -diff --git a/net/netfilter/nf_nat_core.c b/net/netfilter/nf_nat_core.c -index ade527565127..c7625430107d 100644 ---- a/net/netfilter/nf_nat_core.c -+++ b/net/netfilter/nf_nat_core.c -@@ -1105,6 +1105,49 @@ static struct nf_nat_hook nat_hook = { - .manip_pkt = nf_nat_manip_pkt, - }; - -+unsigned int ip_nat_route_input(void *priv, -+ struct sk_buff *skb, -+ const struct nf_hook_state *state) -+{ -+ struct iphdr *iph; -+ struct nf_conn *conn; -+ enum ip_conntrack_info ctinfo; -+ enum ip_conntrack_dir dir; -+ unsigned long statusbit; -+ __be32 saddr; -+ -+ if (!(conn = nf_ct_get(skb, &ctinfo))) -+ return NF_ACCEPT; -+ -+ if (!(conn->status & IPS_NAT_DONE_MASK)) -+ return NF_ACCEPT; -+ dir = CTINFO2DIR(ctinfo); -+ statusbit = IPS_SRC_NAT; -+ if (dir == IP_CT_DIR_REPLY) -+ statusbit ^= IPS_NAT_MASK; -+ if (!(conn->status & statusbit)) -+ return NF_ACCEPT; -+ -+ if (skb_dst(skb)) -+ return NF_ACCEPT; -+ -+ if (skb->len < sizeof(struct iphdr)) -+ return NF_ACCEPT; -+ -+ /* use daddr in other direction as masquerade address (lsrc) */ -+ iph = ip_hdr(skb); -+ saddr = conn->tuplehash[!dir].tuple.dst.u3.ip; -+ if (saddr == iph->saddr) -+ return NF_ACCEPT; -+ -+ if (ip_route_input_lookup(skb, iph->daddr, iph->saddr, iph->tos, -+ skb->dev, saddr)) -+ return NF_DROP; -+ -+ return NF_ACCEPT; -+} -+EXPORT_SYMBOL_GPL(ip_nat_route_input); -+ - static int __init nf_nat_init(void) - { - int ret, i; -diff --git a/security/selinux/nlmsgtab.c b/security/selinux/nlmsgtab.c -index 9cec81209617..820ede89c74a 100644 ---- a/security/selinux/nlmsgtab.c -+++ b/security/selinux/nlmsgtab.c -@@ -83,6 +83,9 @@ static const struct nlmsg_perm nlmsg_route_perms[] = - { RTM_NEWCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_DELCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, - { RTM_GETCHAIN, NETLINK_ROUTE_SOCKET__NLMSG_READ }, -+ { RTM_NEWARPRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, -+ { RTM_DELARPRULE, NETLINK_ROUTE_SOCKET__NLMSG_WRITE }, -+ { RTM_GETARPRULE, NETLINK_ROUTE_SOCKET__NLMSG_READ }, - }; - - static const struct nlmsg_perm nlmsg_tcpdiag_perms[] = -@@ -166,7 +169,7 @@ int selinux_nlmsg_lookup(u16 sclass, u16 nlmsg_type, u32 *perm) - * structures at the top of this file with the new mappings - * before updating the BUILD_BUG_ON() macro! - */ -- BUILD_BUG_ON(RTM_MAX != (RTM_NEWCHAIN + 3)); -+ BUILD_BUG_ON(RTM_MAX != (RTM_NEWARPRULE + 3)); - err = nlmsg_perm(nlmsg_type, perm, nlmsg_route_perms, - sizeof(nlmsg_route_perms)); - break; diff --git a/sys-kernel/boest-v5.0.21/0002-pool-2.6.25-tcp-timewait-20s.diff.patch b/sys-kernel/boest-v5.0.21/0002-pool-2.6.25-tcp-timewait-20s.diff.patch deleted file mode 100644 index f21b1d94..00000000 --- a/sys-kernel/boest-v5.0.21/0002-pool-2.6.25-tcp-timewait-20s.diff.patch +++ /dev/null @@ -1,27 +0,0 @@ -From ef263390526f1c506767146837409982f6791e63 Mon Sep 17 00:00:00 2001 -From: Willy Tarreau <w@1wt.eu> -Date: Sun, 15 Feb 2009 14:51:33 +0100 -Subject: [PATCH 02/12] pool/2.6.25-tcp-timewait-20s.diff - -From http://linux.1wt.eu/alix/kernel-src/2.6.27-wt11/patches-2.6.27-wt11.tar.bz2 - -Signed-off-by: Bertrand Jacquin <bertrand@jacquin.bzh> ---- - include/net/tcp.h | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/include/net/tcp.h b/include/net/tcp.h -index e0a65c067662..4c068f01a812 100644 ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -118,8 +118,8 @@ void tcp_time_wait(struct sock *sk, int state, int timeo); - * initial RTO. - */ - --#define TCP_TIMEWAIT_LEN (60*HZ) /* how long to wait to destroy TIME-WAIT -- * state, about 60 seconds */ -+#define TCP_TIMEWAIT_LEN (20*HZ) /* how long to wait to destroy TIME-WAIT -+ * state, about 20 seconds */ - #define TCP_FIN_TIMEOUT TCP_TIMEWAIT_LEN - /* BSD style FIN_WAIT2 deadlock breaker. - * It used to be 3min, new value is 60sec, diff --git a/sys-kernel/boest-v5.0.21/0003-pool-2.6.25-disable-tcp-debug.diff.patch b/sys-kernel/boest-v5.0.21/0003-pool-2.6.25-disable-tcp-debug.diff.patch deleted file mode 100644 index ed7cf524..00000000 --- a/sys-kernel/boest-v5.0.21/0003-pool-2.6.25-disable-tcp-debug.diff.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 3b5a8b70e6a04fa47e693c5474a27035fd0a0256 Mon Sep 17 00:00:00 2001 -From: Willy Tarreau <w@1wt.eu> -Date: Sun, 15 Feb 2009 14:51:33 +0100 -Subject: [PATCH 03/12] pool/2.6.25-disable-tcp-debug.diff - -From http://linux.1wt.eu/alix/kernel-src/2.6.27-wt11/patches-2.6.27-wt11.tar.bz2 - -Signed-off-by: Bertrand Jacquin <bertrand@jacquin.bzh> ---- - include/net/tcp.h | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/include/net/tcp.h b/include/net/tcp.h -index 4c068f01a812..5835fb7b05b6 100644 ---- a/include/net/tcp.h -+++ b/include/net/tcp.h -@@ -18,7 +18,7 @@ - #ifndef _TCP_H - #define _TCP_H - --#define FASTRETRANS_DEBUG 1 -+#define FASTRETRANS_DEBUG 0 - - #include <linux/list.h> - #include <linux/tcp.h> diff --git a/sys-kernel/boest-v5.0.21/0004-TCP-add-a-sysctl-to-disable-simultaneous-connection-.patch b/sys-kernel/boest-v5.0.21/0004-TCP-add-a-sysctl-to-disable-simultaneous-connection-.patch deleted file mode 100644 index 8ead79bb..00000000 --- a/sys-kernel/boest-v5.0.21/0004-TCP-add-a-sysctl-to-disable-simultaneous-connection-.patch +++ /dev/null @@ -1,142 +0,0 @@ -From 5126e49907cf2d3ffc86476a78d1e06028f9307b Mon Sep 17 00:00:00 2001 -From: Willy Tarreau <w@1wt.eu> -Date: Wed, 8 Oct 2008 10:00:42 +0200 -Subject: [PATCH 04/12] TCP: add a sysctl to disable simultaneous connection - opening. - -Strict implementation of RFC793 (TCP) requires support for a feature -called "simultaneous connect", which allows two clients to connect to -each other without anyone entering a listening state. While almost -never used, and supported by few OSes, Linux supports this feature. - -However, it introduces a weakness in the protocol which makes it very -easy for an attacker to prevent a client from connecting to a known -server. The attacker only has to guess the source port to shut down -the client connection during its establishment. The impact is limited, -but it may be used to prevent an antivirus or IPS from fetching updates -and not detecting an attack, or to prevent an SSL gateway from fetching -a CRL for example. - -This patch provides a new sysctl "tcp_simult_connect" to enable or disable -support for this useless feature. It comes disabled by default. - -Hundreds of systems running with that feature disabled for more than 4 years -have never encountered an application which requires it. It is almost never -supported by firewalls BTW. - -From http://linux.1wt.eu/alix/kernel-src/2.6.27-wt11/patches-2.6.27-wt11.tar.bz2 - -Reviewed-by: Bertrand Jacquin <bertrand@jacquin.bzh> - -Signed-off-by: Willy Tarreau <w@1wt.eu> -Signed-off-by: Bertrand Jacquin <bertrand@jacquin.bzh> ---- - Documentation/networking/ip-sysctl.txt | 22 ++++++++++++++++++++++ - include/net/netns/ipv4.h | 1 + - include/uapi/linux/sysctl.h | 1 + - net/ipv4/sysctl_net_ipv4.c | 7 +++++++ - net/ipv4/tcp_input.c | 6 +++++- - 5 files changed, 36 insertions(+), 1 deletion(-) - -diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt -index 2c9787017dae..9f4d3cd44dbb 100644 ---- a/Documentation/networking/ip-sysctl.txt -+++ b/Documentation/networking/ip-sysctl.txt -@@ -199,6 +199,28 @@ inet_peer_maxttl - INTEGER - - TCP variables: - -+tcp_simult_connect - BOOLEAN -+ Enables TCP simultaneous connect feature conforming to RFC793. -+ Strict implementation of RFC793 (TCP) requires support for a feature -+ called "simultaneous connect", which allows two clients to connect to -+ each other without anyone entering a listening state. While almost -+ never used, and supported by few OSes, Linux supports this feature. -+ -+ However, it introduces a weakness in the protocol which makes it very -+ easy for an attacker to prevent a client from connecting to a known -+ server. The attacker only has to guess the source port to shut down -+ the client connection during its establishment. The impact is limited, -+ but it may be used to prevent an antivirus or IPS from fetching updates -+ and not detecting an attack, or to prevent an SSL gateway from fetching -+ a CRL for example. -+ -+ If you want absolute compatibility with any possible application, -+ you should set it to 1. If you prefer to enhance security on your -+ systems you'd better let it to 0. After four years of usage on -+ hundreds of systems, no application was ever found to require this -+ feature, which is not even supported by most firewalls. -+ Default: 0 -+ - somaxconn - INTEGER - Limit of socket listen() backlog, known in userspace as SOMAXCONN. - Defaults to 128. See also tcp_max_syn_backlog for additional tuning -diff --git a/include/net/netns/ipv4.h b/include/net/netns/ipv4.h -index 7698460a3dd1..74e4fbf9be4f 100644 ---- a/include/net/netns/ipv4.h -+++ b/include/net/netns/ipv4.h -@@ -141,6 +141,7 @@ struct netns_ipv4 { - int sysctl_tcp_recovery; - int sysctl_tcp_thin_linear_timeouts; - int sysctl_tcp_slow_start_after_idle; -+ int sysctl_tcp_simult_connect; - int sysctl_tcp_retrans_collapse; - int sysctl_tcp_stdurg; - int sysctl_tcp_rfc1337; -diff --git a/include/uapi/linux/sysctl.h b/include/uapi/linux/sysctl.h -index 87aa2a6d9125..c94a1099bc5b 100644 ---- a/include/uapi/linux/sysctl.h -+++ b/include/uapi/linux/sysctl.h -@@ -426,6 +426,7 @@ enum - NET_TCP_ALLOWED_CONG_CONTROL=123, - NET_TCP_MAX_SSTHRESH=124, - NET_TCP_FRTO_RESPONSE=125, -+ NET_TCP_SIMULT_CONNECT=126, - }; - - enum { -diff --git a/net/ipv4/sysctl_net_ipv4.c b/net/ipv4/sysctl_net_ipv4.c -index eeb4041fa5f9..5d6345007a7d 100644 ---- a/net/ipv4/sysctl_net_ipv4.c -+++ b/net/ipv4/sysctl_net_ipv4.c -@@ -515,6 +515,13 @@ static struct ctl_table ipv4_table[] = { - .mode = 0444, - .proc_handler = proc_tcp_available_congestion_control, - }, -+ { -+ .procname = "tcp_simult_connect", -+ .data = &init_net.ipv4.sysctl_tcp_simult_connect, -+ .maxlen = sizeof(int), -+ .mode = 0644, -+ .proc_handler = &proc_dointvec, -+ }, - { - .procname = "tcp_allowed_congestion_control", - .maxlen = TCP_CA_BUF_MAX, -diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c -index 95b2e31fff08..156399ec006c 100644 ---- a/net/ipv4/tcp_input.c -+++ b/net/ipv4/tcp_input.c -@@ -5773,6 +5773,7 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, - const struct tcphdr *th) - { - struct inet_connection_sock *icsk = inet_csk(sk); -+ struct net *net = sock_net(sk); - struct tcp_sock *tp = tcp_sk(sk); - struct tcp_fastopen_cookie foc = { .len = -1 }; - int saved_clamp = tp->rx_opt.mss_clamp; -@@ -5928,10 +5929,13 @@ static int tcp_rcv_synsent_state_process(struct sock *sk, struct sk_buff *skb, - tcp_paws_reject(&tp->rx_opt, 0)) - goto discard_and_undo; - -- if (th->syn) { -+ if (th->syn && net->ipv4.sysctl_tcp_simult_connect) { - /* We see SYN without ACK. It is attempt of - * simultaneous connect with crossed SYNs. - * Particularly, it can be connect to self. -+ * This feature is disabled by default as it introduces -+ * weakness in the protocol. It can be enabled by a -+ * sysctl. - */ - tcp_set_state(sk, TCP_SYN_RECV); - diff --git a/sys-kernel/boest-v5.0.21/0005-pool-2.6.25-disable-kbdrate-at-boot.diff.patch b/sys-kernel/boest-v5.0.21/0005-pool-2.6.25-disable-kbdrate-at-boot.diff.patch deleted file mode 100644 index 03eba637..00000000 --- a/sys-kernel/boest-v5.0.21/0005-pool-2.6.25-disable-kbdrate-at-boot.diff.patch +++ /dev/null @@ -1,34 +0,0 @@ -From 848eb1dc9a54a121251e382df6d8c6a5ddbb4f13 Mon Sep 17 00:00:00 2001 -From: Willy Tarreau <w@1wt.eu> -Date: Sun, 15 Feb 2009 14:51:33 +0100 -Subject: [PATCH 05/12] pool/2.6.25-disable-kbdrate-at-boot.diff - -From http://linux.1wt.eu/alix/kernel-src/2.6.27-wt11/patches-2.6.27-wt11.tar.bz2 - -Reviewed-by: Bertrand Jacquin <bertrand@jacquin.bzh> -Signed-off-by: Bertrand Jacquin <bertrand@jacquin.bzh> ---- - arch/x86/boot/main.c | 3 +++ - 1 file changed, 3 insertions(+) - -diff --git a/arch/x86/boot/main.c b/arch/x86/boot/main.c -index 73532543d689..e0d26ecfb713 100644 ---- a/arch/x86/boot/main.c -+++ b/arch/x86/boot/main.c -@@ -64,6 +64,8 @@ static void copy_boot_params(void) - */ - static void keyboard_init(void) - { -+/*This may take several seconds if the system has no kbd controller */ -+#ifdef CONFIG_INPUT_KEYBOARD - struct biosregs ireg, oreg; - initregs(&ireg); - -@@ -73,6 +75,7 @@ static void keyboard_init(void) - - ireg.ax = 0x0305; /* Set keyboard repeat rate */ - intcall(0x16, &ireg, NULL); -+#endif - } - - /* diff --git a/sys-kernel/boest-v5.0.21/0006-Disable-CONFIG_PROCESSOR_SELECT-printk-s.patch b/sys-kernel/boest-v5.0.21/0006-Disable-CONFIG_PROCESSOR_SELECT-printk-s.patch deleted file mode 100644 index e1139b95..00000000 --- a/sys-kernel/boest-v5.0.21/0006-Disable-CONFIG_PROCESSOR_SELECT-printk-s.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 96bdb30d6bad427ffb1a78a97dbc87e8fa9d02b6 Mon Sep 17 00:00:00 2001 -From: Bertrand Jacquin <bertrand@jacquin.bzh> -Date: Wed, 9 Jan 2013 00:28:28 +0100 -Subject: [PATCH 06/12] Disable CONFIG_PROCESSOR_SELECT printk()'s - -Signed-off-by: Bertrand Jacquin <bertrand@jacquin.bzh> ---- - arch/x86/kernel/cpu/common.c | 17 ----------------- - 1 file changed, 17 deletions(-) - -diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c -index 132a63dc5a76..0f9d27df958c 100644 ---- a/arch/x86/kernel/cpu/common.c -+++ b/arch/x86/kernel/cpu/common.c -@@ -1158,10 +1158,6 @@ void __init early_cpu_init(void) - const struct cpu_dev *const *cdev; - int count = 0; - --#ifdef CONFIG_PROCESSOR_SELECT -- pr_info("KERNEL supported cpus:\n"); --#endif -- - for (cdev = __x86_cpu_dev_start; cdev < __x86_cpu_dev_end; cdev++) { - const struct cpu_dev *cpudev = *cdev; - -@@ -1169,19 +1165,6 @@ void __init early_cpu_init(void) - break; - cpu_devs[count] = cpudev; - count++; -- --#ifdef CONFIG_PROCESSOR_SELECT -- { -- unsigned int j; -- -- for (j = 0; j < 2; j++) { -- if (!cpudev->c_ident[j]) -- continue; -- pr_info(" %s %s\n", cpudev->c_vendor, -- cpudev->c_ident[j]); -- } -- } --#endif - } - early_identify_cpu(&boot_cpu_data); - } diff --git a/sys-kernel/boest-v5.0.21/0007-This-patch-adds-support-for-a-restricted-user-contro.patch b/sys-kernel/boest-v5.0.21/0007-This-patch-adds-support-for-a-restricted-user-contro.patch deleted file mode 100644 index 7f19d474..00000000 --- a/sys-kernel/boest-v5.0.21/0007-This-patch-adds-support-for-a-restricted-user-contro.patch +++ /dev/null @@ -1,75 +0,0 @@ -From 7fc0d2ef3ed15c79112122dceb940814ebe46f78 Mon Sep 17 00:00:00 2001 -From: "Anthony G. Basile" <blueness@gentoo.org> -Date: Tue, 15 Jan 2019 10:16:38 -0500 -Subject: [PATCH 07/12] This patch adds support for a restricted - user-controlled namespace on tmpfs filesystem used to house PaX flags. The - namespace must be of the form user.pax.* and its value cannot exceed a size - of 8 bytes. - -This is needed even on all Gentoo systems so that XATTR_PAX flags -are preserved for users who might build packages using portage on -a tmpfs system with a non-hardened kernel and then switch to a -hardened kernel with XATTR_PAX enabled. - -The namespace is added to any user with Extended Attribute support -enabled for tmpfs. Users who do not enable xattrs will not have -the XATTR_PAX flags preserved. ---- - include/uapi/linux/xattr.h | 4 ++++ - mm/shmem.c | 15 +++++++++++++++ - 2 files changed, 19 insertions(+) - -diff --git a/include/uapi/linux/xattr.h b/include/uapi/linux/xattr.h -index c1395b5bd432..bac6d48eca8e 100644 ---- a/include/uapi/linux/xattr.h -+++ b/include/uapi/linux/xattr.h -@@ -77,5 +77,9 @@ - #define XATTR_POSIX_ACL_DEFAULT "posix_acl_default" - #define XATTR_NAME_POSIX_ACL_DEFAULT XATTR_SYSTEM_PREFIX XATTR_POSIX_ACL_DEFAULT - -+/* User namespace */ -+#define XATTR_PAX_PREFIX XATTR_USER_PREFIX "pax." -+#define XATTR_PAX_FLAGS_SUFFIX "flags" -+#define XATTR_NAME_PAX_FLAGS XATTR_PAX_PREFIX XATTR_PAX_FLAGS_SUFFIX - - #endif /* _UAPI_LINUX_XATTR_H */ -diff --git a/mm/shmem.c b/mm/shmem.c -index 2c012eee133d..b8bce7b3c614 100644 ---- a/mm/shmem.c -+++ b/mm/shmem.c -@@ -3140,6 +3140,14 @@ static int shmem_xattr_handler_set(const struct xattr_handler *handler, - struct shmem_inode_info *info = SHMEM_I(inode); - - name = xattr_full_name(handler, name); -+ -+ if (!strncmp(name, XATTR_USER_PREFIX, XATTR_USER_PREFIX_LEN)) { -+ if (strcmp(name, XATTR_NAME_PAX_FLAGS)) -+ return -EOPNOTSUPP; -+ if (size > 8) -+ return -EINVAL; -+ } -+ - return simple_xattr_set(&info->xattrs, name, value, size, flags); - } - -@@ -3155,6 +3163,12 @@ static const struct xattr_handler shmem_trusted_xattr_handler = { - .set = shmem_xattr_handler_set, - }; - -+static const struct xattr_handler shmem_user_xattr_handler = { -+ .prefix = XATTR_USER_PREFIX, -+ .get = shmem_xattr_handler_get, -+ .set = shmem_xattr_handler_set, -+}; -+ - static const struct xattr_handler *shmem_xattr_handlers[] = { - #ifdef CONFIG_TMPFS_POSIX_ACL - &posix_acl_access_xattr_handler, -@@ -3162,6 +3176,7 @@ static const struct xattr_handler *shmem_xattr_handlers[] = { - #endif - &shmem_security_xattr_handler, - &shmem_trusted_xattr_handler, -+ &shmem_user_xattr_handler, - NULL - }; - diff --git a/sys-kernel/boest-v5.0.21/0008-fs-Enable-link-security-restrictions-by-default.patch b/sys-kernel/boest-v5.0.21/0008-fs-Enable-link-security-restrictions-by-default.patch deleted file mode 100644 index fcc60548..00000000 --- a/sys-kernel/boest-v5.0.21/0008-fs-Enable-link-security-restrictions-by-default.patch +++ /dev/null @@ -1,26 +0,0 @@ -From f1159e91944392d8fb2833854570424252d8ad8a Mon Sep 17 00:00:00 2001 -From: Ben Hutchings <ben@decadent.org.uk> -Date: Fri, 2 Nov 2012 05:32:06 +0000 -Subject: [PATCH 08/12] fs: Enable link security restrictions by default - -This reverts commit 561ec64ae67ef25cac8d72bb9c4bfc955edfd415 -('VFS: don't do protected {sym,hard}links by default'). ---- - fs/namei.c | 4 ++-- - 1 file changed, 2 insertions(+), 2 deletions(-) - -diff --git a/fs/namei.c b/fs/namei.c -index 914178cdbe94..bd94f65a9efd 100644 ---- a/fs/namei.c -+++ b/fs/namei.c -@@ -885,8 +885,8 @@ static inline void put_link(struct nameidata *nd) - path_put(&last->link); - } - --int sysctl_protected_symlinks __read_mostly = 0; --int sysctl_protected_hardlinks __read_mostly = 0; -+int sysctl_protected_symlinks __read_mostly = 1; -+int sysctl_protected_hardlinks __read_mostly = 1; - int sysctl_protected_fifos __read_mostly; - int sysctl_protected_regular __read_mostly; - diff --git a/sys-kernel/boest-v5.0.21/0009-usb-storage-Disable-UAS-on-JMicron-SATA-enclosure.patch b/sys-kernel/boest-v5.0.21/0009-usb-storage-Disable-UAS-on-JMicron-SATA-enclosure.patch deleted file mode 100644 index 1c13dacd..00000000 --- a/sys-kernel/boest-v5.0.21/0009-usb-storage-Disable-UAS-on-JMicron-SATA-enclosure.patch +++ /dev/null @@ -1,37 +0,0 @@ -From f715bdcd7844910684679afa63b578272afdf64b Mon Sep 17 00:00:00 2001 -From: Laura Abbott <labbott@fedoraproject.org> -Date: Tue, 8 Sep 2015 09:53:38 -0700 -Subject: [PATCH 09/12] usb-storage: Disable UAS on JMicron SATA enclosure - -Steve Ellis reported incorrect block sizes and alignement -offsets with a SATA enclosure. Adding a quirk to disable -UAS fixes the problems. - -Reported-by: Steven Ellis <sellis@redhat.com> -Signed-off-by: Laura Abbott <labbott@fedoraproject.org> ---- - drivers/usb/storage/unusual_uas.h | 7 +++++-- - 1 file changed, 5 insertions(+), 2 deletions(-) - -diff --git a/drivers/usb/storage/unusual_uas.h b/drivers/usb/storage/unusual_uas.h -index d0bdebd87ce3..1b23741036ee 100644 ---- a/drivers/usb/storage/unusual_uas.h -+++ b/drivers/usb/storage/unusual_uas.h -@@ -87,12 +87,15 @@ UNUSUAL_DEV(0x2537, 0x1068, 0x0000, 0x9999, - USB_SC_DEVICE, USB_PR_DEVICE, NULL, - US_FL_IGNORE_UAS), - --/* Reported-by: Takeo Nakayama <javhera@gmx.com> */ -+/* -+ * Initially Reported-by: Takeo Nakayama <javhera@gmx.com> -+ * UAS Ignore Reported by Steven Ellis <sellis@redhat.com> -+ */ - UNUSUAL_DEV(0x357d, 0x7788, 0x0000, 0x9999, - "JMicron", - "JMS566", - USB_SC_DEVICE, USB_PR_DEVICE, NULL, -- US_FL_NO_REPORT_OPCODES), -+ US_FL_NO_REPORT_OPCODES | US_FL_IGNORE_UAS), - - /* Reported-by: Hans de Goede <hdegoede@redhat.com> */ - UNUSUAL_DEV(0x4971, 0x1012, 0x0000, 0x9999, diff --git a/sys-kernel/boest-v5.0.21/0010-5.0-2600_enable-key-swapping-for-apple-mac.patch.patch b/sys-kernel/boest-v5.0.21/0010-5.0-2600_enable-key-swapping-for-apple-mac.patch.patch deleted file mode 100644 index 59de7f4e..00000000 --- a/sys-kernel/boest-v5.0.21/0010-5.0-2600_enable-key-swapping-for-apple-mac.patch.patch +++ /dev/null @@ -1,125 +0,0 @@ -From b702c4ad56a03d0c79eaf3f8aa38718bb0c5fe30 Mon Sep 17 00:00:00 2001 -From: Mike Pagano <mpagano@gentoo.org> -Date: Tue, 15 Jan 2019 10:16:38 -0500 -Subject: [PATCH 10/12] 5.0:2600_enable-key-swapping-for-apple-mac.patch - ---- - drivers/hid/hid-apple.c | 76 +++++++++++++++++++++++++++++++++++++++-- - 1 file changed, 74 insertions(+), 2 deletions(-) - -diff --git a/drivers/hid/hid-apple.c b/drivers/hid/hid-apple.c -index 1cb41992aaa1..c34a3be5085a 100644 ---- a/drivers/hid/hid-apple.c -+++ b/drivers/hid/hid-apple.c -@@ -54,6 +54,22 @@ MODULE_PARM_DESC(swap_opt_cmd, "Swap the Option (\"Alt\") and Command (\"Flag\") - "(For people who want to keep Windows PC keyboard muscle memory. " - "[0] = as-is, Mac layout. 1 = swapped, Windows layout.)"); - -+static unsigned int swap_fn_leftctrl; -+module_param(swap_fn_leftctrl, uint, 0644); -+MODULE_PARM_DESC(swap_fn_leftctrl, "Swap the Fn and left Control keys. " -+ "(For people who want to keep PC keyboard muscle memory. " -+ "[0] = as-is, Mac layout, 1 = swapped, PC layout)"); -+ -+static unsigned int rightalt_as_rightctrl; -+module_param(rightalt_as_rightctrl, uint, 0644); -+MODULE_PARM_DESC(rightalt_as_rightctrl, "Use the right Alt key as a right Ctrl key. " -+ "[0] = as-is, Mac layout. 1 = Right Alt is right Ctrl"); -+ -+static unsigned int ejectcd_as_delete; -+module_param(ejectcd_as_delete, uint, 0644); -+MODULE_PARM_DESC(ejectcd_as_delete, "Use Eject-CD key as Delete key. " -+ "([0] = disabled, 1 = enabled)"); -+ - struct apple_sc { - unsigned long quirks; - unsigned int fn_on; -@@ -166,6 +182,21 @@ static const struct apple_key_translation swapped_option_cmd_keys[] = { - { } - }; - -+static const struct apple_key_translation swapped_fn_leftctrl_keys[] = { -+ { KEY_FN, KEY_LEFTCTRL }, -+ { } -+}; -+ -+static const struct apple_key_translation rightalt_as_rightctrl_keys[] = { -+ { KEY_RIGHTALT, KEY_RIGHTCTRL }, -+ { } -+}; -+ -+static const struct apple_key_translation ejectcd_as_delete_keys[] = { -+ { KEY_EJECTCD, KEY_DELETE }, -+ { } -+}; -+ - static const struct apple_key_translation *apple_find_translation( - const struct apple_key_translation *table, u16 from) - { -@@ -185,9 +216,11 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, - struct apple_sc *asc = hid_get_drvdata(hid); - const struct apple_key_translation *trans, *table; - -- if (usage->code == KEY_FN) { -+ u16 fn_keycode = (swap_fn_leftctrl) ? (KEY_LEFTCTRL) : (KEY_FN); -+ -+ if (usage->code == fn_keycode) { - asc->fn_on = !!value; -- input_event(input, usage->type, usage->code, value); -+ input_event(input, usage->type, KEY_FN, value); - return 1; - } - -@@ -266,6 +299,30 @@ static int hidinput_apple_event(struct hid_device *hid, struct input_dev *input, - } - } - -+ if (swap_fn_leftctrl) { -+ trans = apple_find_translation(swapped_fn_leftctrl_keys, usage->code); -+ if (trans) { -+ input_event(input, usage->type, trans->to, value); -+ return 1; -+ } -+ } -+ -+ if (ejectcd_as_delete) { -+ trans = apple_find_translation(ejectcd_as_delete_keys, usage->code); -+ if (trans) { -+ input_event(input, usage->type, trans->to, value); -+ return 1; -+ } -+ } -+ -+ if (rightalt_as_rightctrl) { -+ trans = apple_find_translation(rightalt_as_rightctrl_keys, usage->code); -+ if (trans) { -+ input_event(input, usage->type, trans->to, value); -+ return 1; -+ } -+ } -+ - return 0; - } - -@@ -329,6 +386,21 @@ static void apple_setup_input(struct input_dev *input) - - for (trans = apple_iso_keyboard; trans->from; trans++) - set_bit(trans->to, input->keybit); -+ -+ if (swap_fn_leftctrl) { -+ for (trans = swapped_fn_leftctrl_keys; trans->from; trans++) -+ set_bit(trans->to, input->keybit); -+ } -+ -+ if (ejectcd_as_delete) { -+ for (trans = ejectcd_as_delete_keys; trans->from; trans++) -+ set_bit(trans->to, input->keybit); -+ } -+ -+ if (rightalt_as_rightctrl) { -+ for (trans = rightalt_as_rightctrl_keys; trans->from; trans++) -+ set_bit(trans->to, input->keybit); -+ } - } - - static int apple_input_mapping(struct hid_device *hdev, struct hid_input *hi, diff --git a/sys-kernel/boest-v5.0.21/0011-5.0-4567_distro-Gentoo-Kconfig.patch.patch b/sys-kernel/boest-v5.0.21/0011-5.0-4567_distro-Gentoo-Kconfig.patch.patch deleted file mode 100644 index 9500a466..00000000 --- a/sys-kernel/boest-v5.0.21/0011-5.0-4567_distro-Gentoo-Kconfig.patch.patch +++ /dev/null @@ -1,173 +0,0 @@ -From e9eaca9efc5008a4c48503b615d6f1ad90e33839 Mon Sep 17 00:00:00 2001 -From: Mike Pagano <mpagano@gentoo.org> -Date: Fri, 28 Dec 2018 18:58:06 -0500 -Subject: [PATCH 11/12] 5.0:4567_distro-Gentoo-Kconfig.patch - ---- - Kconfig | 2 + - distro/Kconfig | 147 +++++++++++++++++++++++++++++++++++++++++++++++++ - 2 files changed, 149 insertions(+) - -diff --git a/Kconfig b/Kconfig -index 48a80beab685..a5ad73c66099 100644 ---- a/Kconfig -+++ b/Kconfig -@@ -30,3 +30,5 @@ source "crypto/Kconfig" - source "lib/Kconfig" - - source "lib/Kconfig.debug" -+ -+source "distro/Kconfig" -diff --git a/distro/Kconfig b/distro/Kconfig -new file mode 100644 -index 000000000000..57379b7720de ---- /dev/null -+++ b/distro/Kconfig -@@ -0,0 +1,147 @@ -+menu "Gentoo Linux" -+ -+config GENTOO_LINUX -+ bool "Gentoo Linux support" -+ -+ default y -+ -+ help -+ In order to boot Gentoo Linux a minimal set of config settings needs to -+ be enabled in the kernel; to avoid the users from having to enable them -+ manually as part of a Gentoo Linux installation or a new clean config, -+ we enable these config settings by default for convenience. -+ -+ See the settings that become available for more details and fine-tuning. -+ -+config GENTOO_LINUX_UDEV -+ bool "Linux dynamic and persistent device naming (userspace devfs) support" -+ -+ depends on GENTOO_LINUX -+ default y if GENTOO_LINUX -+ -+ select DEVTMPFS -+ select TMPFS -+ select UNIX -+ -+ select MMU -+ select SHMEM -+ -+ help -+ In order to boot Gentoo Linux a minimal set of config settings needs to -+ be enabled in the kernel; to avoid the users from having to enable them -+ manually as part of a Gentoo Linux installation or a new clean config, -+ we enable these config settings by default for convenience. -+ -+ Currently this only selects TMPFS, DEVTMPFS and their dependencies. -+ TMPFS is enabled to maintain a tmpfs file system at /dev/shm, /run and -+ /sys/fs/cgroup; DEVTMPFS to maintain a devtmpfs file system at /dev. -+ -+ Some of these are critical files that need to be available early in the -+ boot process; if not available, it causes sysfs and udev to malfunction. -+ -+ To ensure Gentoo Linux boots, it is best to leave this setting enabled; -+ if you run a custom setup, you could consider whether to disable this. -+ -+config GENTOO_LINUX_PORTAGE -+ bool "Select options required by Portage features" -+ -+ depends on GENTOO_LINUX -+ default y if GENTOO_LINUX -+ -+ select CGROUPS -+ select NAMESPACES -+ select IPC_NS -+ select NET_NS -+ select PID_NS -+ select SYSVIPC -+ -+ help -+ This enables options required by various Portage FEATURES. -+ Currently this selects: -+ -+ CGROUPS (required for FEATURES=cgroup) -+ IPC_NS (required for FEATURES=ipc-sandbox) -+ NET_NS (required for FEATURES=network-sandbox) -+ PID_NS (required for FEATURES=pid-sandbox) -+ SYSVIPC (required by IPC_NS) -+ -+ -+ It is highly recommended that you leave this enabled as these FEATURES -+ are, or will soon be, enabled by default. -+ -+menu "Support for init systems, system and service managers" -+ visible if GENTOO_LINUX -+ -+config GENTOO_LINUX_INIT_SCRIPT -+ bool "OpenRC, runit and other script based systems and managers" -+ -+ default y if GENTOO_LINUX -+ -+ depends on GENTOO_LINUX -+ -+ select BINFMT_SCRIPT -+ -+ help -+ The init system is the first thing that loads after the kernel booted. -+ -+ These config settings allow you to select which init systems to support; -+ instead of having to select all the individual settings all over the -+ place, these settings allows you to select all the settings at once. -+ -+ This particular setting enables all the known requirements for OpenRC, -+ runit and similar script based systems and managers. -+ -+ If you are unsure about this, it is best to leave this setting enabled. -+ -+config GENTOO_LINUX_INIT_SYSTEMD -+ bool "systemd" -+ -+ default n -+ -+ depends on GENTOO_LINUX && GENTOO_LINUX_UDEV -+ -+ select AUTOFS4_FS -+ select BLK_DEV_BSG -+ select CGROUPS -+ select CHECKPOINT_RESTORE -+ select CRYPTO_HMAC -+ select CRYPTO_SHA256 -+ select CRYPTO_USER_API_HASH -+ select DEVPTS_MULTIPLE_INSTANCES -+ select DMIID if X86_32 || X86_64 || X86 -+ select EPOLL -+ select FANOTIFY -+ select FHANDLE -+ select INOTIFY_USER -+ select IPV6 -+ select NET -+ select NET_NS -+ select PROC_FS -+ select SECCOMP -+ select SECCOMP_FILTER -+ select SIGNALFD -+ select SYSFS -+ select TIMERFD -+ select TMPFS_POSIX_ACL -+ select TMPFS_XATTR -+ -+ select ANON_INODES -+ select BLOCK -+ select EVENTFD -+ select FSNOTIFY -+ select INET -+ select NLATTR -+ -+ help -+ The init system is the first thing that loads after the kernel booted. -+ -+ These config settings allow you to select which init systems to support; -+ instead of having to select all the individual settings all over the -+ place, these settings allows you to select all the settings at once. -+ -+ This particular setting enables all the known requirements for systemd; -+ it also enables suggested optional settings, as the package suggests to. -+ -+endmenu -+ -+endmenu diff --git a/sys-kernel/boest-v5.0.21/0012-WARNING.patch b/sys-kernel/boest-v5.0.21/0012-WARNING.patch deleted file mode 100644 index 09c49dad..00000000 --- a/sys-kernel/boest-v5.0.21/0012-WARNING.patch +++ /dev/null @@ -1,565 +0,0 @@ -From 637b2594cc18d455d80b67ba564f1d7931109aec Mon Sep 17 00:00:00 2001 -From: Mike Pagano <mpagano@gentoo.org> -Date: Mon, 4 Mar 2019 08:10:52 -0500 -Subject: [PATCH 12/12] WARNING This patch works with gcc versions 4.9+ and - with kernel version 4.13+ and should NOT be applied when compiling on older - versions of gcc due to key name changes of the march flags introduced with - the version 4.9 release of gcc.[1] - -Use the older version of this patch hosted on the same github for older -versions of gcc. - -FEATURES -This patch adds additional CPU options to the Linux kernel accessible under: - Processor type and features ---> - Processor family ---> - -The expanded microarchitectures include: -* AMD Improved K8-family -* AMD K10-family -* AMD Family 10h (Barcelona) -* AMD Family 14h (Bobcat) -* AMD Family 16h (Jaguar) -* AMD Family 15h (Bulldozer) -* AMD Family 15h (Piledriver) -* AMD Family 15h (Steamroller) -* AMD Family 15h (Excavator) -* AMD Family 17h (Zen) -* Intel Silvermont low-power processors -* Intel 1st Gen Core i3/i5/i7 (Nehalem) -* Intel 1.5 Gen Core i3/i5/i7 (Westmere) -* Intel 2nd Gen Core i3/i5/i7 (Sandybridge) -* Intel 3rd Gen Core i3/i5/i7 (Ivybridge) -* Intel 4th Gen Core i3/i5/i7 (Haswell) -* Intel 5th Gen Core i3/i5/i7 (Broadwell) -* Intel 6th Gen Core i3/i5/i7 (Skylake) -* Intel 6th Gen Core i7/i9 (Skylake X) - -It also offers to compile passing the 'native' option which, "selects the CPU -to generate code for at compilation time by determining the processor type of -the compiling machine. Using -march=native enables all instruction subsets -supported by the local machine and will produce code optimized for the local -machine under the constraints of the selected instruction set."[3] - -MINOR NOTES -This patch also changes 'atom' to 'bonnell' in accordance with the gcc v4.9 -changes. Note that upstream is using the deprecated 'match=atom' flags when I -believe it should use the newer 'march=bonnell' flag for atom processors.[2] - -It is not recommended to compile on Atom-CPUs with the 'native' option.[4] The -recommendation is to use the 'atom' option instead. - -BENEFITS -Small but real speed increases are measurable using a make endpoint comparing -a generic kernel to one built with one of the respective microarchs. - -See the following experimental evidence supporting this statement: -https://github.com/graysky2/kernel_gcc_patch - -REQUIREMENTS -linux version >=4.13 -gcc version >=4.9 - -ACKNOWLEDGMENTS -This patch builds on the seminal work by Jeroen.[5] - -REFERENCES -1. https://gcc.gnu.org/gcc-4.9/changes.html -2. https://bugzilla.kernel.org/show_bug.cgi?id=77461 -3. https://gcc.gnu.org/onlinedocs/gcc/x86-Options.html -4. https://github.com/graysky2/kernel_gcc_patch/issues/15 -5. http://www.linuxforge.net/docs/linux/linux-gcc.php ---- - arch/x86/Kconfig.cpu | 235 +++++++++++++++++++++++++++++----- - arch/x86/Makefile | 35 ++++- - arch/x86/Makefile_32.cpu | 24 +++- - arch/x86/include/asm/module.h | 40 ++++++ - 4 files changed, 297 insertions(+), 37 deletions(-) - -diff --git a/arch/x86/Kconfig.cpu b/arch/x86/Kconfig.cpu -index 6adce15268bd..7d0709e548af 100644 ---- a/arch/x86/Kconfig.cpu -+++ b/arch/x86/Kconfig.cpu -@@ -116,6 +116,7 @@ config MPENTIUMM - config MPENTIUM4 - bool "Pentium-4/Celeron(P4-based)/Pentium-4 M/older Xeon" - depends on X86_32 -+ select X86_P6_NOP - ---help--- - Select this for Intel Pentium 4 chips. This includes the - Pentium 4, Pentium D, P4-based Celeron and Xeon, and -@@ -148,9 +149,8 @@ config MPENTIUM4 - -Paxville - -Dempsey - -- - config MK6 -- bool "K6/K6-II/K6-III" -+ bool "AMD K6/K6-II/K6-III" - depends on X86_32 - ---help--- - Select this for an AMD K6-family processor. Enables use of -@@ -158,7 +158,7 @@ config MK6 - flags to GCC. - - config MK7 -- bool "Athlon/Duron/K7" -+ bool "AMD Athlon/Duron/K7" - depends on X86_32 - ---help--- - Select this for an AMD Athlon K7-family processor. Enables use of -@@ -166,12 +166,83 @@ config MK7 - flags to GCC. - - config MK8 -- bool "Opteron/Athlon64/Hammer/K8" -+ bool "AMD Opteron/Athlon64/Hammer/K8" - ---help--- - Select this for an AMD Opteron or Athlon64 Hammer-family processor. - Enables use of some extended instructions, and passes appropriate - optimization flags to GCC. - -+config MK8SSE3 -+ bool "AMD Opteron/Athlon64/Hammer/K8 with SSE3" -+ ---help--- -+ Select this for improved AMD Opteron or Athlon64 Hammer-family processors. -+ Enables use of some extended instructions, and passes appropriate -+ optimization flags to GCC. -+ -+config MK10 -+ bool "AMD 61xx/7x50/PhenomX3/X4/II/K10" -+ ---help--- -+ Select this for an AMD 61xx Eight-Core Magny-Cours, Athlon X2 7x50, -+ Phenom X3/X4/II, Athlon II X2/X3/X4, or Turion II-family processor. -+ Enables use of some extended instructions, and passes appropriate -+ optimization flags to GCC. -+ -+config MBARCELONA -+ bool "AMD Barcelona" -+ ---help--- -+ Select this for AMD Family 10h Barcelona processors. -+ -+ Enables -march=barcelona -+ -+config MBOBCAT -+ bool "AMD Bobcat" -+ ---help--- -+ Select this for AMD Family 14h Bobcat processors. -+ -+ Enables -march=btver1 -+ -+config MJAGUAR -+ bool "AMD Jaguar" -+ ---help--- -+ Select this for AMD Family 16h Jaguar processors. -+ -+ Enables -march=btver2 -+ -+config MBULLDOZER -+ bool "AMD Bulldozer" -+ ---help--- -+ Select this for AMD Family 15h Bulldozer processors. -+ -+ Enables -march=bdver1 -+ -+config MPILEDRIVER -+ bool "AMD Piledriver" -+ ---help--- -+ Select this for AMD Family 15h Piledriver processors. -+ -+ Enables -march=bdver2 -+ -+config MSTEAMROLLER -+ bool "AMD Steamroller" -+ ---help--- -+ Select this for AMD Family 15h Steamroller processors. -+ -+ Enables -march=bdver3 -+ -+config MEXCAVATOR -+ bool "AMD Excavator" -+ ---help--- -+ Select this for AMD Family 15h Excavator processors. -+ -+ Enables -march=bdver4 -+ -+config MZEN -+ bool "AMD Zen" -+ ---help--- -+ Select this for AMD Family 17h Zen processors. -+ -+ Enables -march=znver1 -+ - config MCRUSOE - bool "Crusoe" - depends on X86_32 -@@ -253,6 +324,7 @@ config MVIAC7 - - config MPSC - bool "Intel P4 / older Netburst based Xeon" -+ select X86_P6_NOP - depends on X86_64 - ---help--- - Optimize for Intel Pentium 4, Pentium D and older Nocona/Dempsey -@@ -262,17 +334,9 @@ config MPSC - using the cpu family field - in /proc/cpuinfo. Family 15 is an older Xeon, Family 6 a newer one. - --config MCORE2 -- bool "Core 2/newer Xeon" -- ---help--- -- -- Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and -- 53xx) CPUs. You can distinguish newer from older Xeons by the CPU -- family in /proc/cpuinfo. Newer ones have 6 and older ones 15 -- (not a typo) -- - config MATOM - bool "Intel Atom" -+ select X86_P6_NOP - ---help--- - - Select this for the Intel Atom platform. Intel Atom CPUs have an -@@ -280,6 +344,99 @@ config MATOM - accordingly optimized code. Use a recent GCC with specific Atom - support in order to fully benefit from selecting this option. - -+config MCORE2 -+ bool "Intel Core 2" -+ select X86_P6_NOP -+ ---help--- -+ -+ Select this for Intel Core 2 and newer Core 2 Xeons (Xeon 51xx and -+ 53xx) CPUs. You can distinguish newer from older Xeons by the CPU -+ family in /proc/cpuinfo. Newer ones have 6 and older ones 15 -+ (not a typo) -+ -+ Enables -march=core2 -+ -+config MNEHALEM -+ bool "Intel Nehalem" -+ select X86_P6_NOP -+ ---help--- -+ -+ Select this for 1st Gen Core processors in the Nehalem family. -+ -+ Enables -march=nehalem -+ -+config MWESTMERE -+ bool "Intel Westmere" -+ select X86_P6_NOP -+ ---help--- -+ -+ Select this for the Intel Westmere formerly Nehalem-C family. -+ -+ Enables -march=westmere -+ -+config MSILVERMONT -+ bool "Intel Silvermont" -+ select X86_P6_NOP -+ ---help--- -+ -+ Select this for the Intel Silvermont platform. -+ -+ Enables -march=silvermont -+ -+config MSANDYBRIDGE -+ bool "Intel Sandy Bridge" -+ select X86_P6_NOP -+ ---help--- -+ -+ Select this for 2nd Gen Core processors in the Sandy Bridge family. -+ -+ Enables -march=sandybridge -+ -+config MIVYBRIDGE -+ bool "Intel Ivy Bridge" -+ select X86_P6_NOP -+ ---help--- -+ -+ Select this for 3rd Gen Core processors in the Ivy Bridge family. -+ -+ Enables -march=ivybridge -+ -+config MHASWELL -+ bool "Intel Haswell" -+ select X86_P6_NOP -+ ---help--- -+ -+ Select this for 4th Gen Core processors in the Haswell family. -+ -+ Enables -march=haswell -+ -+config MBROADWELL -+ bool "Intel Broadwell" -+ select X86_P6_NOP -+ ---help--- -+ -+ Select this for 5th Gen Core processors in the Broadwell family. -+ -+ Enables -march=broadwell -+ -+config MSKYLAKE -+ bool "Intel Skylake" -+ select X86_P6_NOP -+ ---help--- -+ -+ Select this for 6th Gen Core processors in the Skylake family. -+ -+ Enables -march=skylake -+ -+config MSKYLAKEX -+ bool "Intel Skylake X" -+ select X86_P6_NOP -+ ---help--- -+ -+ Select this for 6th Gen Core processors in the Skylake X family. -+ -+ Enables -march=skylake-avx512 -+ - config GENERIC_CPU - bool "Generic-x86-64" - depends on X86_64 -@@ -287,6 +444,19 @@ config GENERIC_CPU - Generic x86-64 CPU. - Run equally well on all x86-64 CPUs. - -+config MNATIVE -+ bool "Native optimizations autodetected by GCC" -+ ---help--- -+ -+ GCC 4.2 and above support -march=native, which automatically detects -+ the optimum settings to use based on your processor. -march=native -+ also detects and applies additional settings beyond -march specific -+ to your CPU, (eg. -msse4). Unless you have a specific reason not to -+ (e.g. distcc cross-compiling), you should probably be using -+ -march=native rather than anything listed below. -+ -+ Enables -march=native -+ - endchoice - - config X86_GENERIC -@@ -311,7 +481,7 @@ config X86_INTERNODE_CACHE_SHIFT - config X86_L1_CACHE_SHIFT - int - default "7" if MPENTIUM4 || MPSC -- default "6" if MK7 || MK8 || MPENTIUMM || MCORE2 || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU -+ default "6" if MK7 || MK8 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MJAGUAR || MPENTIUMM || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MNATIVE || MATOM || MVIAC7 || X86_GENERIC || GENERIC_CPU - default "4" if MELAN || M486 || MGEODEGX1 - default "5" if MWINCHIP3D || MWINCHIPC6 || MCRUSOE || MEFFICEON || MCYRIXIII || MK6 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || MVIAC3_2 || MGEODE_LX - -@@ -329,35 +499,36 @@ config X86_ALIGNMENT_16 - - config X86_INTEL_USERCOPY - def_bool y -- depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK7 || MEFFICEON || MCORE2 -+ depends on MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M586MMX || X86_GENERIC || MK8 || MK8SSE3 || MK7 || MEFFICEON || MCORE2 || MK10 || MBARCELONA || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MNATIVE - - config X86_USE_PPRO_CHECKSUM - def_bool y -- depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MATOM -+ depends on MWINCHIP3D || MWINCHIPC6 || MCYRIXIII || MK7 || MK6 || MK10 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MK8 || MK8SSE3 || MVIAC3_2 || MVIAC7 || MEFFICEON || MGEODE_LX || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MATOM || MNATIVE - - config X86_USE_3DNOW - def_bool y - depends on (MCYRIXIII || MK7 || MGEODE_LX) && !UML - --# --# P6_NOPs are a relatively minor optimization that require a family >= --# 6 processor, except that it is broken on certain VIA chips. --# Furthermore, AMD chips prefer a totally different sequence of NOPs --# (which work on all CPUs). In addition, it looks like Virtual PC --# does not understand them. --# --# As a result, disallow these if we're not compiling for X86_64 (these --# NOPs do work on all x86-64 capable chips); the list of processors in --# the right-hand clause are the cores that benefit from this optimization. --# - config X86_P6_NOP -- def_bool y -- depends on X86_64 -- depends on (MCORE2 || MPENTIUM4 || MPSC) -+ default n -+ bool "Support for P6_NOPs on Intel chips" -+ depends on (MCORE2 || MPENTIUM4 || MPSC || MATOM || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MNATIVE) -+ ---help--- -+ P6_NOPs are a relatively minor optimization that require a family >= -+ 6 processor, except that it is broken on certain VIA chips. -+ Furthermore, AMD chips prefer a totally different sequence of NOPs -+ (which work on all CPUs). In addition, it looks like Virtual PC -+ does not understand them. -+ -+ As a result, disallow these if we're not compiling for X86_64 (these -+ NOPs do work on all x86-64 capable chips); the list of processors in -+ the right-hand clause are the cores that benefit from this optimization. -+ -+ Say Y if you have Intel CPU newer than Pentium Pro, N otherwise. - - config X86_TSC - def_bool y -- depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MATOM) || X86_64 -+ depends on (MWINCHIP3D || MCRUSOE || MEFFICEON || MCYRIXIII || MK7 || MK6 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || MK8 || MK8SSE3 || MVIAC3_2 || MVIAC7 || MGEODEGX1 || MGEODE_LX || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MNATIVE || MATOM) || X86_64 - - config X86_CMPXCHG64 - def_bool y -@@ -367,7 +538,7 @@ config X86_CMPXCHG64 - # generates cmov. - config X86_CMOV - def_bool y -- depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MATOM || MGEODE_LX) -+ depends on (MK8 || MK8SSE3 || MK10 || MBARCELONA || MBOBCAT || MBULLDOZER || MPILEDRIVER || MSTEAMROLLER || MEXCAVATOR || MZEN || MJAGUAR || MK7 || MCORE2 || MNEHALEM || MWESTMERE || MSILVERMONT || MSANDYBRIDGE || MIVYBRIDGE || MHASWELL || MBROADWELL || MSKYLAKE || MSKYLAKEX || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || MCRUSOE || MEFFICEON || X86_64 || MNATIVE || MATOM || MGEODE_LX) - - config X86_MINIMUM_CPU_FAMILY - int -diff --git a/arch/x86/Makefile b/arch/x86/Makefile -index 2cf52617a1e7..62f9bb23fa76 100644 ---- a/arch/x86/Makefile -+++ b/arch/x86/Makefile -@@ -118,13 +118,42 @@ else - KBUILD_CFLAGS += $(call cc-option,-mskip-rax-setup) - - # FIXME - should be integrated in Makefile.cpu (Makefile_32.cpu) -+ cflags-$(CONFIG_MNATIVE) += $(call cc-option,-march=native) - cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8) -+ cflags-$(CONFIG_MK8SSE3) += $(call cc-option,-march=k8-sse3,-mtune=k8) -+ cflags-$(CONFIG_MK10) += $(call cc-option,-march=amdfam10) -+ cflags-$(CONFIG_MBARCELONA) += $(call cc-option,-march=barcelona) -+ cflags-$(CONFIG_MBOBCAT) += $(call cc-option,-march=btver1) -+ cflags-$(CONFIG_MJAGUAR) += $(call cc-option,-march=btver2) -+ cflags-$(CONFIG_MBULLDOZER) += $(call cc-option,-march=bdver1) -+ cflags-$(CONFIG_MPILEDRIVER) += $(call cc-option,-march=bdver2) -+ cflags-$(CONFIG_MSTEAMROLLER) += $(call cc-option,-march=bdver3) -+ cflags-$(CONFIG_MEXCAVATOR) += $(call cc-option,-march=bdver4) -+ cflags-$(CONFIG_MZEN) += $(call cc-option,-march=znver1) - cflags-$(CONFIG_MPSC) += $(call cc-option,-march=nocona) - - cflags-$(CONFIG_MCORE2) += \ -- $(call cc-option,-march=core2,$(call cc-option,-mtune=generic)) -- cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom) \ -- $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic)) -+ $(call cc-option,-march=core2,$(call cc-option,-mtune=core2)) -+ cflags-$(CONFIG_MNEHALEM) += \ -+ $(call cc-option,-march=nehalem,$(call cc-option,-mtune=nehalem)) -+ cflags-$(CONFIG_MWESTMERE) += \ -+ $(call cc-option,-march=westmere,$(call cc-option,-mtune=westmere)) -+ cflags-$(CONFIG_MSILVERMONT) += \ -+ $(call cc-option,-march=silvermont,$(call cc-option,-mtune=silvermont)) -+ cflags-$(CONFIG_MSANDYBRIDGE) += \ -+ $(call cc-option,-march=sandybridge,$(call cc-option,-mtune=sandybridge)) -+ cflags-$(CONFIG_MIVYBRIDGE) += \ -+ $(call cc-option,-march=ivybridge,$(call cc-option,-mtune=ivybridge)) -+ cflags-$(CONFIG_MHASWELL) += \ -+ $(call cc-option,-march=haswell,$(call cc-option,-mtune=haswell)) -+ cflags-$(CONFIG_MBROADWELL) += \ -+ $(call cc-option,-march=broadwell,$(call cc-option,-mtune=broadwell)) -+ cflags-$(CONFIG_MSKYLAKE) += \ -+ $(call cc-option,-march=skylake,$(call cc-option,-mtune=skylake)) -+ cflags-$(CONFIG_MSKYLAKEX) += \ -+ $(call cc-option,-march=skylake-avx512,$(call cc-option,-mtune=skylake-avx512)) -+ cflags-$(CONFIG_MATOM) += $(call cc-option,-march=bonnell) \ -+ $(call cc-option,-mtune=bonnell,$(call cc-option,-mtune=generic)) - cflags-$(CONFIG_GENERIC_CPU) += $(call cc-option,-mtune=generic) - KBUILD_CFLAGS += $(cflags-y) - -diff --git a/arch/x86/Makefile_32.cpu b/arch/x86/Makefile_32.cpu -index 1f5faf8606b4..4a3a27cedc75 100644 ---- a/arch/x86/Makefile_32.cpu -+++ b/arch/x86/Makefile_32.cpu -@@ -23,7 +23,18 @@ cflags-$(CONFIG_MK6) += -march=k6 - # Please note, that patches that add -march=athlon-xp and friends are pointless. - # They make zero difference whatsosever to performance at this time. - cflags-$(CONFIG_MK7) += -march=athlon -+cflags-$(CONFIG_MNATIVE) += $(call cc-option,-march=native) - cflags-$(CONFIG_MK8) += $(call cc-option,-march=k8,-march=athlon) -+cflags-$(CONFIG_MK8SSE3) += $(call cc-option,-march=k8-sse3,-march=athlon) -+cflags-$(CONFIG_MK10) += $(call cc-option,-march=amdfam10,-march=athlon) -+cflags-$(CONFIG_MBARCELONA) += $(call cc-option,-march=barcelona,-march=athlon) -+cflags-$(CONFIG_MBOBCAT) += $(call cc-option,-march=btver1,-march=athlon) -+cflags-$(CONFIG_MJAGUAR) += $(call cc-option,-march=btver2,-march=athlon) -+cflags-$(CONFIG_MBULLDOZER) += $(call cc-option,-march=bdver1,-march=athlon) -+cflags-$(CONFIG_MPILEDRIVER) += $(call cc-option,-march=bdver2,-march=athlon) -+cflags-$(CONFIG_MSTEAMROLLER) += $(call cc-option,-march=bdver3,-march=athlon) -+cflags-$(CONFIG_MEXCAVATOR) += $(call cc-option,-march=bdver4,-march=athlon) -+cflags-$(CONFIG_MZEN) += $(call cc-option,-march=znver1,-march=athlon) - cflags-$(CONFIG_MCRUSOE) += -march=i686 -falign-functions=0 -falign-jumps=0 -falign-loops=0 - cflags-$(CONFIG_MEFFICEON) += -march=i686 $(call tune,pentium3) -falign-functions=0 -falign-jumps=0 -falign-loops=0 - cflags-$(CONFIG_MWINCHIPC6) += $(call cc-option,-march=winchip-c6,-march=i586) -@@ -32,8 +43,17 @@ cflags-$(CONFIG_MCYRIXIII) += $(call cc-option,-march=c3,-march=i486) -falign-fu - cflags-$(CONFIG_MVIAC3_2) += $(call cc-option,-march=c3-2,-march=i686) - cflags-$(CONFIG_MVIAC7) += -march=i686 - cflags-$(CONFIG_MCORE2) += -march=i686 $(call tune,core2) --cflags-$(CONFIG_MATOM) += $(call cc-option,-march=atom,$(call cc-option,-march=core2,-march=i686)) \ -- $(call cc-option,-mtune=atom,$(call cc-option,-mtune=generic)) -+cflags-$(CONFIG_MNEHALEM) += -march=i686 $(call tune,nehalem) -+cflags-$(CONFIG_MWESTMERE) += -march=i686 $(call tune,westmere) -+cflags-$(CONFIG_MSILVERMONT) += -march=i686 $(call tune,silvermont) -+cflags-$(CONFIG_MSANDYBRIDGE) += -march=i686 $(call tune,sandybridge) -+cflags-$(CONFIG_MIVYBRIDGE) += -march=i686 $(call tune,ivybridge) -+cflags-$(CONFIG_MHASWELL) += -march=i686 $(call tune,haswell) -+cflags-$(CONFIG_MBROADWELL) += -march=i686 $(call tune,broadwell) -+cflags-$(CONFIG_MSKYLAKE) += -march=i686 $(call tune,skylake) -+cflags-$(CONFIG_MSKYLAKEX) += -march=i686 $(call tune,skylake-avx512) -+cflags-$(CONFIG_MATOM) += $(call cc-option,-march=bonnell,$(call cc-option,-march=core2,-march=i686)) \ -+ $(call cc-option,-mtune=bonnell,$(call cc-option,-mtune=generic)) - - # AMD Elan support - cflags-$(CONFIG_MELAN) += -march=i486 -diff --git a/arch/x86/include/asm/module.h b/arch/x86/include/asm/module.h -index 7948a17febb4..22c53c8b844b 100644 ---- a/arch/x86/include/asm/module.h -+++ b/arch/x86/include/asm/module.h -@@ -25,6 +25,26 @@ struct mod_arch_specific { - #define MODULE_PROC_FAMILY "586MMX " - #elif defined CONFIG_MCORE2 - #define MODULE_PROC_FAMILY "CORE2 " -+#elif defined CONFIG_MNATIVE -+#define MODULE_PROC_FAMILY "NATIVE " -+#elif defined CONFIG_MNEHALEM -+#define MODULE_PROC_FAMILY "NEHALEM " -+#elif defined CONFIG_MWESTMERE -+#define MODULE_PROC_FAMILY "WESTMERE " -+#elif defined CONFIG_MSILVERMONT -+#define MODULE_PROC_FAMILY "SILVERMONT " -+#elif defined CONFIG_MSANDYBRIDGE -+#define MODULE_PROC_FAMILY "SANDYBRIDGE " -+#elif defined CONFIG_MIVYBRIDGE -+#define MODULE_PROC_FAMILY "IVYBRIDGE " -+#elif defined CONFIG_MHASWELL -+#define MODULE_PROC_FAMILY "HASWELL " -+#elif defined CONFIG_MBROADWELL -+#define MODULE_PROC_FAMILY "BROADWELL " -+#elif defined CONFIG_MSKYLAKE -+#define MODULE_PROC_FAMILY "SKYLAKE " -+#elif defined CONFIG_MSKYLAKEX -+#define MODULE_PROC_FAMILY "SKYLAKEX " - #elif defined CONFIG_MATOM - #define MODULE_PROC_FAMILY "ATOM " - #elif defined CONFIG_M686 -@@ -43,6 +63,26 @@ struct mod_arch_specific { - #define MODULE_PROC_FAMILY "K7 " - #elif defined CONFIG_MK8 - #define MODULE_PROC_FAMILY "K8 " -+#elif defined CONFIG_MK8SSE3 -+#define MODULE_PROC_FAMILY "K8SSE3 " -+#elif defined CONFIG_MK10 -+#define MODULE_PROC_FAMILY "K10 " -+#elif defined CONFIG_MBARCELONA -+#define MODULE_PROC_FAMILY "BARCELONA " -+#elif defined CONFIG_MBOBCAT -+#define MODULE_PROC_FAMILY "BOBCAT " -+#elif defined CONFIG_MBULLDOZER -+#define MODULE_PROC_FAMILY "BULLDOZER " -+#elif defined CONFIG_MPILEDRIVER -+#define MODULE_PROC_FAMILY "PILEDRIVER " -+#elif defined CONFIG_MSTEAMROLLER -+#define MODULE_PROC_FAMILY "STEAMROLLER " -+#elif defined CONFIG_MJAGUAR -+#define MODULE_PROC_FAMILY "JAGUAR " -+#elif defined CONFIG_MEXCAVATOR -+#define MODULE_PROC_FAMILY "EXCAVATOR " -+#elif defined CONFIG_MZEN -+#define MODULE_PROC_FAMILY "ZEN " - #elif defined CONFIG_MELAN - #define MODULE_PROC_FAMILY "ELAN " - #elif defined CONFIG_MCRUSOE diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0001-arm-partially-revert-702b94bff3c50542a6e4ab9a4f4cef0.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0001-arm-partially-revert-702b94bff3c50542a6e4ab9a4f4cef0.patch deleted file mode 100644 index 953ae639..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0001-arm-partially-revert-702b94bff3c50542a6e4ab9a4f4cef0.patch +++ /dev/null @@ -1,107 +0,0 @@ -From bfcbe989feadf2b5c0936aec2a5a07669dd40681 Mon Sep 17 00:00:00 2001 -From: Dan Pasanen <dan.pasanen@gmail.com> -Date: Thu, 21 Sep 2017 09:55:42 -0500 -Subject: [PATCH 001/325] arm: partially revert - 702b94bff3c50542a6e4ab9a4f4cef093262fe65 - -* Re-expose some dmi APIs for use in VCSM ---- - arch/arm/include/asm/cacheflush.h | 21 +++++++++++++++++++++ - arch/arm/include/asm/glue-cache.h | 2 ++ - arch/arm/mm/proc-macros.S | 2 ++ - arch/arm/mm/proc-syms.c | 3 +++ - 4 files changed, 28 insertions(+) - -diff --git a/arch/arm/include/asm/cacheflush.h b/arch/arm/include/asm/cacheflush.h -index ec1a5fd0d294..dc0a32fdde43 100644 ---- a/arch/arm/include/asm/cacheflush.h -+++ b/arch/arm/include/asm/cacheflush.h -@@ -94,6 +94,21 @@ - * DMA Cache Coherency - * =================== - * -+ * dma_inv_range(start, end) -+ * -+ * Invalidate (discard) the specified virtual address range. -+ * May not write back any entries. If 'start' or 'end' -+ * are not cache line aligned, those lines must be written -+ * back. -+ * - start - virtual start address -+ * - end - virtual end address -+ * -+ * dma_clean_range(start, end) -+ * -+ * Clean (write back) the specified virtual address range. -+ * - start - virtual start address -+ * - end - virtual end address -+ * - * dma_flush_range(start, end) - * - * Clean and invalidate the specified virtual address range. -@@ -115,6 +130,8 @@ struct cpu_cache_fns { - void (*dma_map_area)(const void *, size_t, int); - void (*dma_unmap_area)(const void *, size_t, int); - -+ void (*dma_inv_range)(const void *, const void *); -+ void (*dma_clean_range)(const void *, const void *); - void (*dma_flush_range)(const void *, const void *); - } __no_randomize_layout; - -@@ -140,6 +157,8 @@ extern struct cpu_cache_fns cpu_cache; - * is visible to DMA, or data written by DMA to system memory is - * visible to the CPU. - */ -+#define dmac_inv_range cpu_cache.dma_inv_range -+#define dmac_clean_range cpu_cache.dma_clean_range - #define dmac_flush_range cpu_cache.dma_flush_range - - #else -@@ -159,6 +178,8 @@ extern void __cpuc_flush_dcache_area(void *, size_t); - * is visible to DMA, or data written by DMA to system memory is - * visible to the CPU. - */ -+extern void dmac_inv_range(const void *, const void *); -+extern void dmac_clean_range(const void *, const void *); - extern void dmac_flush_range(const void *, const void *); - - #endif -diff --git a/arch/arm/include/asm/glue-cache.h b/arch/arm/include/asm/glue-cache.h -index 8d1f498e5dd8..0050d2246da8 100644 ---- a/arch/arm/include/asm/glue-cache.h -+++ b/arch/arm/include/asm/glue-cache.h -@@ -158,6 +158,8 @@ static inline void nop_dma_unmap_area(const void *s, size_t l, int f) { } - #define __cpuc_coherent_user_range __glue(_CACHE,_coherent_user_range) - #define __cpuc_flush_dcache_area __glue(_CACHE,_flush_kern_dcache_area) - -+#define dmac_inv_range __glue(_CACHE,_dma_inv_range) -+#define dmac_clean_range __glue(_CACHE,_dma_clean_range) - #define dmac_flush_range __glue(_CACHE,_dma_flush_range) - #endif - -diff --git a/arch/arm/mm/proc-macros.S b/arch/arm/mm/proc-macros.S -index 5461d589a1e2..8d1d479a86fa 100644 ---- a/arch/arm/mm/proc-macros.S -+++ b/arch/arm/mm/proc-macros.S -@@ -335,6 +335,8 @@ ENTRY(\name\()_cache_fns) - .long \name\()_flush_kern_dcache_area - .long \name\()_dma_map_area - .long \name\()_dma_unmap_area -+ .long \name\()_dma_inv_range -+ .long \name\()_dma_clean_range - .long \name\()_dma_flush_range - .size \name\()_cache_fns, . - \name\()_cache_fns - .endm -diff --git a/arch/arm/mm/proc-syms.c b/arch/arm/mm/proc-syms.c -index 054b491ff764..70e8b7d34434 100644 ---- a/arch/arm/mm/proc-syms.c -+++ b/arch/arm/mm/proc-syms.c -@@ -30,6 +30,9 @@ EXPORT_SYMBOL(__cpuc_flush_user_all); - EXPORT_SYMBOL(__cpuc_flush_user_range); - EXPORT_SYMBOL(__cpuc_coherent_kern_range); - EXPORT_SYMBOL(__cpuc_flush_dcache_area); -+EXPORT_SYMBOL(dmac_inv_range); -+EXPORT_SYMBOL(dmac_clean_range); -+EXPORT_SYMBOL(dmac_flush_range); - #else - EXPORT_SYMBOL(cpu_cache); - #endif diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0002-Revert-rtc-pcf8523-properly-handle-oscillator-stop-b.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0002-Revert-rtc-pcf8523-properly-handle-oscillator-stop-b.patch deleted file mode 100644 index 38d6653a..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0002-Revert-rtc-pcf8523-properly-handle-oscillator-stop-b.patch +++ /dev/null @@ -1,58 +0,0 @@ -From 1afa1fe89845f5348aca093471172dc77d615961 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Mon, 29 Oct 2018 14:45:45 +0000 -Subject: [PATCH 002/325] Revert "rtc: pcf8523: properly handle oscillator stop - bit" - -This reverts commit ede44c908d44b166a5b6bd7caacd105c2ff5a70f. - -See: https://github.com/raspberrypi/firmware/issues/1065 - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - drivers/rtc/rtc-pcf8523.c | 25 ++++++++++++++++++++++--- - 1 file changed, 22 insertions(+), 3 deletions(-) - -diff --git a/drivers/rtc/rtc-pcf8523.c b/drivers/rtc/rtc-pcf8523.c -index 3fcd2cbafc84..5abfcaf5c937 100644 ---- a/drivers/rtc/rtc-pcf8523.c -+++ b/drivers/rtc/rtc-pcf8523.c -@@ -201,8 +201,28 @@ static int pcf8523_rtc_read_time(struct device *dev, struct rtc_time *tm) - if (err < 0) - return err; - -- if (regs[0] & REG_SECONDS_OS) -- return -EINVAL; -+ if (regs[0] & REG_SECONDS_OS) { -+ /* -+ * If the oscillator was stopped, try to clear the flag. Upon -+ * power-up the flag is always set, but if we cannot clear it -+ * the oscillator isn't running properly for some reason. The -+ * sensible thing therefore is to return an error, signalling -+ * that the clock cannot be assumed to be correct. -+ */ -+ -+ regs[0] &= ~REG_SECONDS_OS; -+ -+ err = pcf8523_write(client, REG_SECONDS, regs[0]); -+ if (err < 0) -+ return err; -+ -+ err = pcf8523_read(client, REG_SECONDS, ®s[0]); -+ if (err < 0) -+ return err; -+ -+ if (regs[0] & REG_SECONDS_OS) -+ return -EAGAIN; -+ } - - tm->tm_sec = bcd2bin(regs[0] & 0x7f); - tm->tm_min = bcd2bin(regs[1] & 0x7f); -@@ -238,7 +258,6 @@ static int pcf8523_rtc_set_time(struct device *dev, struct rtc_time *tm) - return err; - - regs[0] = REG_SECONDS; -- /* This will purposely overwrite REG_SECONDS_OS */ - regs[1] = bin2bcd(tm->tm_sec); - regs[2] = bin2bcd(tm->tm_min); - regs[3] = bin2bcd(tm->tm_hour); diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0003-smsx95xx-fix-crimes-against-truesize.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0003-smsx95xx-fix-crimes-against-truesize.patch deleted file mode 100644 index 4c332ecf..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0003-smsx95xx-fix-crimes-against-truesize.patch +++ /dev/null @@ -1,49 +0,0 @@ -From 5fdccd8152fb8f6f26a4a297cb06c49cc5688595 Mon Sep 17 00:00:00 2001 -From: Steve Glendinning <steve.glendinning@smsc.com> -Date: Thu, 19 Feb 2015 18:47:12 +0000 -Subject: [PATCH 003/325] smsx95xx: fix crimes against truesize - -smsc95xx is adjusting truesize when it shouldn't, and following a recent patch from Eric this is now triggering warnings. - -This patch stops smsc95xx from changing truesize. - -Signed-off-by: Steve Glendinning <steve.glendinning@smsc.com> ---- - drivers/net/usb/smsc95xx.c | 10 ++++++++-- - 1 file changed, 8 insertions(+), 2 deletions(-) - -diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c -index e3d08626828e..3d6276566a13 100644 ---- a/drivers/net/usb/smsc95xx.c -+++ b/drivers/net/usb/smsc95xx.c -@@ -82,6 +82,10 @@ static bool turbo_mode = true; - module_param(turbo_mode, bool, 0644); - MODULE_PARM_DESC(turbo_mode, "Enable multiple frames per Rx transaction"); - -+static bool truesize_mode = false; -+module_param(truesize_mode, bool, 0644); -+MODULE_PARM_DESC(truesize_mode, "Report larger truesize value"); -+ - static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index, - u32 *data, int in_pm) - { -@@ -1969,7 +1973,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) - if (dev->net->features & NETIF_F_RXCSUM) - smsc95xx_rx_csum_offload(skb); - skb_trim(skb, skb->len - 4); /* remove fcs */ -- skb->truesize = size + sizeof(struct sk_buff); -+ if (truesize_mode) -+ skb->truesize = size + sizeof(struct sk_buff); - - return 1; - } -@@ -1987,7 +1992,8 @@ static int smsc95xx_rx_fixup(struct usbnet *dev, struct sk_buff *skb) - if (dev->net->features & NETIF_F_RXCSUM) - smsc95xx_rx_csum_offload(ax_skb); - skb_trim(ax_skb, ax_skb->len - 4); /* remove fcs */ -- ax_skb->truesize = size + sizeof(struct sk_buff); -+ if (truesize_mode) -+ ax_skb->truesize = size + sizeof(struct sk_buff); - - usbnet_skb_return(dev, ax_skb); - } diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0004-smsc95xx-Experimental-Enable-turbo_mode-and-packetsi.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0004-smsc95xx-Experimental-Enable-turbo_mode-and-packetsi.patch deleted file mode 100644 index dab4baf8..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0004-smsc95xx-Experimental-Enable-turbo_mode-and-packetsi.patch +++ /dev/null @@ -1,45 +0,0 @@ -From 9a17aae354b2f8f16dda782808aa183997bd5745 Mon Sep 17 00:00:00 2001 -From: Sam Nazarko <email@samnazarko.co.uk> -Date: Fri, 1 Apr 2016 17:27:21 +0100 -Subject: [PATCH 004/325] smsc95xx: Experimental: Enable turbo_mode and - packetsize=2560 by default - -See: http://forum.kodi.tv/showthread.php?tid=285288 ---- - drivers/net/usb/smsc95xx.c | 14 +++++++++----- - 1 file changed, 9 insertions(+), 5 deletions(-) - -diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c -index 3d6276566a13..df3c6bd751bf 100644 ---- a/drivers/net/usb/smsc95xx.c -+++ b/drivers/net/usb/smsc95xx.c -@@ -86,6 +86,10 @@ static bool truesize_mode = false; - module_param(truesize_mode, bool, 0644); - MODULE_PARM_DESC(truesize_mode, "Report larger truesize value"); - -+static int packetsize = 2560; -+module_param(packetsize, int, 0644); -+MODULE_PARM_DESC(packetsize, "Override the RX URB packet size"); -+ - static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index, - u32 *data, int in_pm) - { -@@ -1107,13 +1111,13 @@ static int smsc95xx_reset(struct usbnet *dev) - - if (!turbo_mode) { - burst_cap = 0; -- dev->rx_urb_size = MAX_SINGLE_PACKET_SIZE; -+ dev->rx_urb_size = packetsize ? packetsize : MAX_SINGLE_PACKET_SIZE; - } else if (dev->udev->speed == USB_SPEED_HIGH) { -- burst_cap = DEFAULT_HS_BURST_CAP_SIZE / HS_USB_PKT_SIZE; -- dev->rx_urb_size = DEFAULT_HS_BURST_CAP_SIZE; -+ dev->rx_urb_size = packetsize ? packetsize : DEFAULT_HS_BURST_CAP_SIZE; -+ burst_cap = dev->rx_urb_size / HS_USB_PKT_SIZE; - } else { -- burst_cap = DEFAULT_FS_BURST_CAP_SIZE / FS_USB_PKT_SIZE; -- dev->rx_urb_size = DEFAULT_FS_BURST_CAP_SIZE; -+ dev->rx_urb_size = packetsize ? packetsize : DEFAULT_FS_BURST_CAP_SIZE; -+ burst_cap = dev->rx_urb_size / FS_USB_PKT_SIZE; - } - - netif_dbg(dev, ifup, dev->net, "rx_urb_size=%ld\n", diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0005-Allow-mac-address-to-be-set-in-smsc95xx.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0005-Allow-mac-address-to-be-set-in-smsc95xx.patch deleted file mode 100644 index 6dfba5bf..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0005-Allow-mac-address-to-be-set-in-smsc95xx.patch +++ /dev/null @@ -1,98 +0,0 @@ -From 8af4fefe7dfee21e941aa7bbf3a87362baa2a227 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Tue, 26 Mar 2013 17:26:38 +0000 -Subject: [PATCH 005/325] Allow mac address to be set in smsc95xx - -Signed-off-by: popcornmix <popcornmix@gmail.com> ---- - drivers/net/usb/smsc95xx.c | 56 ++++++++++++++++++++++++++++++++++++++ - 1 file changed, 56 insertions(+) - -diff --git a/drivers/net/usb/smsc95xx.c b/drivers/net/usb/smsc95xx.c -index df3c6bd751bf..2dd5f72ad8b1 100644 ---- a/drivers/net/usb/smsc95xx.c -+++ b/drivers/net/usb/smsc95xx.c -@@ -60,6 +60,7 @@ - #define SUSPEND_SUSPEND3 (0x08) - #define SUSPEND_ALLMODES (SUSPEND_SUSPEND0 | SUSPEND_SUSPEND1 | \ - SUSPEND_SUSPEND2 | SUSPEND_SUSPEND3) -+#define MAC_ADDR_LEN (6) - - #define CARRIER_CHECK_DELAY (2 * HZ) - -@@ -90,6 +91,10 @@ static int packetsize = 2560; - module_param(packetsize, int, 0644); - MODULE_PARM_DESC(packetsize, "Override the RX URB packet size"); - -+static char *macaddr = ":"; -+module_param(macaddr, charp, 0); -+MODULE_PARM_DESC(macaddr, "MAC address"); -+ - static int __must_check __smsc95xx_read_reg(struct usbnet *dev, u32 index, - u32 *data, int in_pm) - { -@@ -919,6 +924,53 @@ static int smsc95xx_ioctl(struct net_device *netdev, struct ifreq *rq, int cmd) - return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL); - } - -+/* Check the macaddr module parameter for a MAC address */ -+static int smsc95xx_is_macaddr_param(struct usbnet *dev, u8 *dev_mac) -+{ -+ int i, j, got_num, num; -+ u8 mtbl[MAC_ADDR_LEN]; -+ -+ if (macaddr[0] == ':') -+ return 0; -+ -+ i = 0; -+ j = 0; -+ num = 0; -+ got_num = 0; -+ while (j < MAC_ADDR_LEN) { -+ if (macaddr[i] && macaddr[i] != ':') { -+ got_num++; -+ if ('0' <= macaddr[i] && macaddr[i] <= '9') -+ num = num * 16 + macaddr[i] - '0'; -+ else if ('A' <= macaddr[i] && macaddr[i] <= 'F') -+ num = num * 16 + 10 + macaddr[i] - 'A'; -+ else if ('a' <= macaddr[i] && macaddr[i] <= 'f') -+ num = num * 16 + 10 + macaddr[i] - 'a'; -+ else -+ break; -+ i++; -+ } else if (got_num == 2) { -+ mtbl[j++] = (u8) num; -+ num = 0; -+ got_num = 0; -+ i++; -+ } else { -+ break; -+ } -+ } -+ -+ if (j == MAC_ADDR_LEN) { -+ netif_dbg(dev, ifup, dev->net, "Overriding MAC address with: " -+ "%02x:%02x:%02x:%02x:%02x:%02x\n", mtbl[0], mtbl[1], mtbl[2], -+ mtbl[3], mtbl[4], mtbl[5]); -+ for (i = 0; i < MAC_ADDR_LEN; i++) -+ dev_mac[i] = mtbl[i]; -+ return 1; -+ } else { -+ return 0; -+ } -+} -+ - static void smsc95xx_init_mac_address(struct usbnet *dev) - { - const u8 *mac_addr; -@@ -940,6 +992,10 @@ static void smsc95xx_init_mac_address(struct usbnet *dev) - } - } - -+ /* Check module parameters */ -+ if (smsc95xx_is_macaddr_param(dev, dev->net->dev_addr)) -+ return; -+ - /* no useful static MAC address found. generate a random one */ - eth_hw_addr_random(dev->net); - netif_dbg(dev, ifup, dev->net, "MAC address set to eth_random_addr\n"); diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0006-Protect-__release_resource-against-resources-without.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0006-Protect-__release_resource-against-resources-without.patch deleted file mode 100644 index e821ac6c..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0006-Protect-__release_resource-against-resources-without.patch +++ /dev/null @@ -1,30 +0,0 @@ -From 84ff08f55034c711c1888fafce6cb7a09d8e74cd Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Fri, 13 Mar 2015 12:43:36 +0000 -Subject: [PATCH 006/325] Protect __release_resource against resources without - parents - -Without this patch, removing a device tree overlay can crash here. - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - kernel/resource.c | 6 ++++++ - 1 file changed, 6 insertions(+) - -diff --git a/kernel/resource.c b/kernel/resource.c -index ca7ed5158cff..b7407b33736b 100644 ---- a/kernel/resource.c -+++ b/kernel/resource.c -@@ -213,6 +213,12 @@ static int __release_resource(struct resource *old, bool release_child) - { - struct resource *tmp, **p, *chd; - -+ if (!old->parent) { -+ WARN(old->sibling, "sibling but no parent"); -+ if (old->sibling) -+ return -EINVAL; -+ return 0; -+ } - p = &old->parent->child; - for (;;) { - tmp = *p; diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0007-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0007-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch deleted file mode 100644 index 4d6e9dff..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0007-irq-bcm2836-Prevent-spurious-interrupts-and-trap-the.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 8c0e535a3a2f4a90fce16569e61e2038e2665a66 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Fri, 4 Dec 2015 17:41:50 +0000 -Subject: [PATCH 007/325] irq-bcm2836: Prevent spurious interrupts, and trap - them early - -The old arch-specific IRQ macros included a dsb to ensure the -write to clear the mailbox interrupt completed before returning -from the interrupt. The BCM2836 irqchip driver needs the same -precaution to avoid spurious interrupts. - -Spurious interrupts are still possible for other reasons, -though, so trap them early. ---- - drivers/irqchip/irq-bcm2836.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c -index 2038693f074c..597d36ba601e 100644 ---- a/drivers/irqchip/irq-bcm2836.c -+++ b/drivers/irqchip/irq-bcm2836.c -@@ -135,6 +135,7 @@ __exception_irq_entry bcm2836_arm_irqchip_handle_irq(struct pt_regs *regs) - u32 ipi = ffs(mbox_val) - 1; - - writel(1 << ipi, mailbox0); -+ dsb(sy); - handle_IPI(ipi, regs); - #endif - } else if (stat) { diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0008-irq-bcm2836-Avoid-Invalid-trigger-warning.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0008-irq-bcm2836-Avoid-Invalid-trigger-warning.patch deleted file mode 100644 index ff162f3b..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0008-irq-bcm2836-Avoid-Invalid-trigger-warning.patch +++ /dev/null @@ -1,26 +0,0 @@ -From 76ad1a2a56b144989f899ce4c0a8aab06a0cb392 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Thu, 9 Feb 2017 14:33:30 +0000 -Subject: [PATCH 008/325] irq-bcm2836: Avoid "Invalid trigger warning" - -Initialise the level for each IRQ to avoid a warning from the -arm arch timer code. - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - drivers/irqchip/irq-bcm2836.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c -index 597d36ba601e..c006a8ac10d5 100644 ---- a/drivers/irqchip/irq-bcm2836.c -+++ b/drivers/irqchip/irq-bcm2836.c -@@ -115,7 +115,7 @@ static int bcm2836_map(struct irq_domain *d, unsigned int irq, - irq_set_percpu_devid(irq); - irq_domain_set_info(d, irq, hw, chip, d->host_data, - handle_percpu_devid_irq, NULL, NULL); -- irq_set_status_flags(irq, IRQ_NOAUTOEN); -+ irq_set_status_flags(irq, IRQ_NOAUTOEN | IRQ_TYPE_LEVEL_LOW); - - return 0; - } diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0009-irqchip-bcm2835-Add-FIQ-support.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0009-irqchip-bcm2835-Add-FIQ-support.patch deleted file mode 100644 index e99d3e2e..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0009-irqchip-bcm2835-Add-FIQ-support.patch +++ /dev/null @@ -1,131 +0,0 @@ -From 1bb63ef451bff77ab24a49bc7508508fbaf06cb6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> -Date: Fri, 12 Jun 2015 19:01:05 +0200 -Subject: [PATCH 009/325] irqchip: bcm2835: Add FIQ support -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Add a duplicate irq range with an offset on the hwirq's so the -driver can detect that enable_fiq() is used. -Tested with downstream dwc_otg USB controller driver. - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> -Reviewed-by: Eric Anholt <eric@anholt.net> -Acked-by: Stephen Warren <swarren@wwwdotorg.org> ---- - arch/arm/mach-bcm/Kconfig | 1 + - drivers/irqchip/irq-bcm2835.c | 51 +++++++++++++++++++++++++++++++---- - 2 files changed, 47 insertions(+), 5 deletions(-) - -diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig -index a067adf9f1ee..9ca6f33d4440 100644 ---- a/arch/arm/mach-bcm/Kconfig -+++ b/arch/arm/mach-bcm/Kconfig -@@ -165,6 +165,7 @@ config ARCH_BCM2835 - select HAVE_ARM_ARCH_TIMER if ARCH_MULTI_V7 - select TIMER_OF - select BCM2835_TIMER -+ select FIQ - select PINCTRL - select PINCTRL_BCM2835 - help -diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c -index 418245d31921..64472b25d0b4 100644 ---- a/drivers/irqchip/irq-bcm2835.c -+++ b/drivers/irqchip/irq-bcm2835.c -@@ -45,7 +45,7 @@ - #include <asm/exception.h> - - /* Put the bank and irq (32 bits) into the hwirq */ --#define MAKE_HWIRQ(b, n) ((b << 5) | (n)) -+#define MAKE_HWIRQ(b, n) (((b) << 5) | (n)) - #define HWIRQ_BANK(i) (i >> 5) - #define HWIRQ_BIT(i) BIT(i & 0x1f) - -@@ -61,9 +61,13 @@ - | SHORTCUT1_MASK | SHORTCUT2_MASK) - - #define REG_FIQ_CONTROL 0x0c -+#define REG_FIQ_ENABLE 0x80 -+#define REG_FIQ_DISABLE 0 - - #define NR_BANKS 3 - #define IRQS_PER_BANK 32 -+#define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0) -+#define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0)) - - static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 }; - static const int reg_enable[] __initconst = { 0x18, 0x10, 0x14 }; -@@ -88,14 +92,38 @@ static void __exception_irq_entry bcm2835_handle_irq( - struct pt_regs *regs); - static void bcm2836_chained_handle_irq(struct irq_desc *desc); - -+static inline unsigned int hwirq_to_fiq(unsigned long hwirq) -+{ -+ hwirq -= NUMBER_IRQS; -+ /* -+ * The hwirq numbering used in this driver is: -+ * BASE (0-7) GPU1 (32-63) GPU2 (64-95). -+ * This differ from the one used in the FIQ register: -+ * GPU1 (0-31) GPU2 (32-63) BASE (64-71) -+ */ -+ if (hwirq >= 32) -+ return hwirq - 32; -+ -+ return hwirq + 64; -+} -+ - static void armctrl_mask_irq(struct irq_data *d) - { -- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.disable[HWIRQ_BANK(d->hwirq)]); -+ if (d->hwirq >= NUMBER_IRQS) -+ writel_relaxed(REG_FIQ_DISABLE, intc.base + REG_FIQ_CONTROL); -+ else -+ writel_relaxed(HWIRQ_BIT(d->hwirq), -+ intc.disable[HWIRQ_BANK(d->hwirq)]); - } - - static void armctrl_unmask_irq(struct irq_data *d) - { -- writel_relaxed(HWIRQ_BIT(d->hwirq), intc.enable[HWIRQ_BANK(d->hwirq)]); -+ if (d->hwirq >= NUMBER_IRQS) -+ writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq), -+ intc.base + REG_FIQ_CONTROL); -+ else -+ writel_relaxed(HWIRQ_BIT(d->hwirq), -+ intc.enable[HWIRQ_BANK(d->hwirq)]); - } - - static struct irq_chip armctrl_chip = { -@@ -140,8 +168,9 @@ static int __init armctrl_of_init(struct device_node *node, - if (!base) - panic("%pOF: unable to map IC registers\n", node); - -- intc.domain = irq_domain_add_linear(node, MAKE_HWIRQ(NR_BANKS, 0), -- &armctrl_ops, NULL); -+ intc.base = base; -+ intc.domain = irq_domain_add_linear(node, NUMBER_IRQS * 2, -+ &armctrl_ops, NULL); - if (!intc.domain) - panic("%pOF: unable to create IRQ domain\n", node); - -@@ -171,6 +200,18 @@ static int __init armctrl_of_init(struct device_node *node, - set_handle_irq(bcm2835_handle_irq); - } - -+ /* Make a duplicate irq range which is used to enable FIQ */ -+ for (b = 0; b < NR_BANKS; b++) { -+ for (i = 0; i < bank_irqs[b]; i++) { -+ irq = irq_create_mapping(intc.domain, -+ MAKE_HWIRQ(b, i) + NUMBER_IRQS); -+ BUG_ON(irq <= 0); -+ irq_set_chip(irq, &armctrl_chip); -+ set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); -+ } -+ } -+ init_FIQ(FIQ_START); -+ - return 0; - } - diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0010-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0010-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch deleted file mode 100644 index b9225403..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0010-irqchip-irq-bcm2835-Add-2836-FIQ-support.patch +++ /dev/null @@ -1,101 +0,0 @@ -From 3bb70341a3bd22d10c4f2e3a793b1f0c71ccb13d Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> -Date: Fri, 23 Oct 2015 16:26:55 +0200 -Subject: [PATCH 010/325] irqchip: irq-bcm2835: Add 2836 FIQ support -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> ---- - drivers/irqchip/irq-bcm2835.c | 43 +++++++++++++++++++++++++++++++++-- - 1 file changed, 41 insertions(+), 2 deletions(-) - -diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c -index 64472b25d0b4..2fccc5cfe9f3 100644 ---- a/drivers/irqchip/irq-bcm2835.c -+++ b/drivers/irqchip/irq-bcm2835.c -@@ -41,8 +41,11 @@ - #include <linux/of_irq.h> - #include <linux/irqchip.h> - #include <linux/irqdomain.h> -+#include <linux/mfd/syscon.h> -+#include <linux/regmap.h> - - #include <asm/exception.h> -+#include <asm/mach/irq.h> - - /* Put the bank and irq (32 bits) into the hwirq */ - #define MAKE_HWIRQ(b, n) (((b) << 5) | (n)) -@@ -60,6 +63,9 @@ - #define BANK0_VALID_MASK (BANK0_HWIRQ_MASK | BANK1_HWIRQ | BANK2_HWIRQ \ - | SHORTCUT1_MASK | SHORTCUT2_MASK) - -+#undef ARM_LOCAL_GPU_INT_ROUTING -+#define ARM_LOCAL_GPU_INT_ROUTING 0x0c -+ - #define REG_FIQ_CONTROL 0x0c - #define REG_FIQ_ENABLE 0x80 - #define REG_FIQ_DISABLE 0 -@@ -85,6 +91,7 @@ struct armctrl_ic { - void __iomem *enable[NR_BANKS]; - void __iomem *disable[NR_BANKS]; - struct irq_domain *domain; -+ struct regmap *local_regmap; - }; - - static struct armctrl_ic intc __read_mostly; -@@ -118,12 +125,35 @@ static void armctrl_mask_irq(struct irq_data *d) - - static void armctrl_unmask_irq(struct irq_data *d) - { -- if (d->hwirq >= NUMBER_IRQS) -+ if (d->hwirq >= NUMBER_IRQS) { -+ if (num_online_cpus() > 1) { -+ unsigned int data; -+ int ret; -+ -+ if (!intc.local_regmap) { -+ pr_err("FIQ is disabled due to missing regmap\n"); -+ return; -+ } -+ -+ ret = regmap_read(intc.local_regmap, -+ ARM_LOCAL_GPU_INT_ROUTING, &data); -+ if (ret) { -+ pr_err("Failed to read int routing %d\n", ret); -+ return; -+ } -+ -+ data &= ~0xc; -+ data |= (1 << 2); -+ regmap_write(intc.local_regmap, -+ ARM_LOCAL_GPU_INT_ROUTING, data); -+ } -+ - writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq), - intc.base + REG_FIQ_CONTROL); -- else -+ } else { - writel_relaxed(HWIRQ_BIT(d->hwirq), - intc.enable[HWIRQ_BANK(d->hwirq)]); -+ } - } - - static struct irq_chip armctrl_chip = { -@@ -200,6 +230,15 @@ static int __init armctrl_of_init(struct device_node *node, - set_handle_irq(bcm2835_handle_irq); - } - -+ if (is_2836) { -+ intc.local_regmap = -+ syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local"); -+ if (IS_ERR(intc.local_regmap)) { -+ pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n"); -+ intc.local_regmap = NULL; -+ } -+ } -+ - /* Make a duplicate irq range which is used to enable FIQ */ - for (b = 0; b < NR_BANKS; b++) { - for (i = 0; i < bank_irqs[b]; i++) { diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0011-spi-spidev-Completely-disable-the-spidev-warning.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0011-spi-spidev-Completely-disable-the-spidev-warning.patch deleted file mode 100644 index 39812dce..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0011-spi-spidev-Completely-disable-the-spidev-warning.patch +++ /dev/null @@ -1,26 +0,0 @@ -From f3a7257d1e9adaf616b050ff0ba4cfb4366d6400 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Tue, 14 Jul 2015 10:26:09 +0100 -Subject: [PATCH 011/325] spi: spidev: Completely disable the spidev warning - -An alternative strategy would be to use "rpi,spidev" instead, but that -would require many Raspberry Pi Device Tree changes. - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - drivers/spi/spidev.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/spi/spidev.c b/drivers/spi/spidev.c -index b0c76e2626ce..b0657fdfe171 100644 ---- a/drivers/spi/spidev.c -+++ b/drivers/spi/spidev.c -@@ -725,7 +725,7 @@ static int spidev_probe(struct spi_device *spi) - * compatible string, it is a Linux implementation thing - * rather than a description of the hardware. - */ -- WARN(spi->dev.of_node && -+ WARN(0 && spi->dev.of_node && - of_device_is_compatible(spi->dev.of_node, "spidev"), - "%pOF: buggy DT: spidev listed directly in DT\n", spi->dev.of_node); - diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0012-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0012-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch deleted file mode 100644 index 2b7b36e7..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0012-dmaengine-bcm2835-Load-driver-early-and-support-lega.patch +++ /dev/null @@ -1,105 +0,0 @@ -From 9e04fa0be55736189e848fa7fddc339269e0871e Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> -Date: Sat, 3 Oct 2015 22:22:55 +0200 -Subject: [PATCH 012/325] dmaengine: bcm2835: Load driver early and support - legacy API -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Load driver early since at least bcm2708_fb doesn't support deferred -probing and even if it did, we don't want the video driver deferred. -Support the legacy DMA API which is needed by bcm2708_fb. -Don't mask out channel 2. - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> ---- - drivers/dma/Kconfig | 2 +- - drivers/dma/bcm2835-dma.c | 26 +++++++++++++++++++++++++- - 2 files changed, 26 insertions(+), 2 deletions(-) - -diff --git a/drivers/dma/Kconfig b/drivers/dma/Kconfig -index d2286c7f7222..518761906c72 100644 ---- a/drivers/dma/Kconfig -+++ b/drivers/dma/Kconfig -@@ -131,7 +131,7 @@ config COH901318 - - config DMA_BCM2835 - tristate "BCM2835 DMA engine support" -- depends on ARCH_BCM2835 -+ depends on ARCH_BCM2835 || ARCH_BCM2708 || ARCH_BCM2709 - select DMA_ENGINE - select DMA_VIRTUAL_CHANNELS - -diff --git a/drivers/dma/bcm2835-dma.c b/drivers/dma/bcm2835-dma.c -index bf5119203637..7af3a88b42ff 100644 ---- a/drivers/dma/bcm2835-dma.c -+++ b/drivers/dma/bcm2835-dma.c -@@ -28,6 +28,7 @@ - #include <linux/interrupt.h> - #include <linux/list.h> - #include <linux/module.h> -+#include <linux/platform_data/dma-bcm2708.h> - #include <linux/platform_device.h> - #include <linux/slab.h> - #include <linux/io.h> -@@ -39,6 +40,7 @@ - - #define BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED 14 - #define BCM2835_DMA_CHAN_NAME_SIZE 8 -+#define BCM2835_DMA_BULK_MASK BIT(0) - - struct bcm2835_dmadev { - struct dma_device ddev; -@@ -895,6 +897,9 @@ static int bcm2835_dma_probe(struct platform_device *pdev) - base = devm_ioremap_resource(&pdev->dev, res); - if (IS_ERR(base)) - return PTR_ERR(base); -+ rc = bcm_dmaman_probe(pdev, base, BCM2835_DMA_BULK_MASK); -+ if (rc) -+ dev_err(&pdev->dev, "Failed to initialize the legacy API\n"); - - od->base = base; - -@@ -933,6 +938,9 @@ static int bcm2835_dma_probe(struct platform_device *pdev) - goto err_no_dma; - } - -+ /* Channel 0 is used by the legacy API */ -+ chans_available &= ~BCM2835_DMA_BULK_MASK; -+ - /* get irqs for each channel that we support */ - for (i = 0; i <= BCM2835_DMA_MAX_DMA_CHAN_SUPPORTED; i++) { - /* skip masked out channels */ -@@ -1007,6 +1015,7 @@ static int bcm2835_dma_remove(struct platform_device *pdev) - { - struct bcm2835_dmadev *od = platform_get_drvdata(pdev); - -+ bcm_dmaman_remove(pdev); - dma_async_device_unregister(&od->ddev); - bcm2835_dma_free(od); - -@@ -1022,7 +1031,22 @@ static struct platform_driver bcm2835_dma_driver = { - }, - }; - --module_platform_driver(bcm2835_dma_driver); -+static int bcm2835_dma_init(void) -+{ -+ return platform_driver_register(&bcm2835_dma_driver); -+} -+ -+static void bcm2835_dma_exit(void) -+{ -+ platform_driver_unregister(&bcm2835_dma_driver); -+} -+ -+/* -+ * Load after serial driver (arch_initcall) so we see the messages if it fails, -+ * but before drivers (module_init) that need a DMA channel. -+ */ -+subsys_initcall(bcm2835_dma_init); -+module_exit(bcm2835_dma_exit); - - MODULE_ALIAS("platform:bcm2835-dma"); - MODULE_DESCRIPTION("BCM2835 DMA engine driver"); diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0013-firmware-Updated-mailbox-header.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0013-firmware-Updated-mailbox-header.patch deleted file mode 100644 index 2f8e0747..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0013-firmware-Updated-mailbox-header.patch +++ /dev/null @@ -1,38 +0,0 @@ -From 4bbdcdaadbcfd768c4546e4fd806c8f8b90dd39a Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Mon, 25 Jan 2016 17:25:12 +0000 -Subject: [PATCH 013/325] firmware: Updated mailbox header - ---- - include/soc/bcm2835/raspberrypi-firmware.h | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/include/soc/bcm2835/raspberrypi-firmware.h b/include/soc/bcm2835/raspberrypi-firmware.h -index 4be1aa4435ae..dc4217788705 100644 ---- a/include/soc/bcm2835/raspberrypi-firmware.h -+++ b/include/soc/bcm2835/raspberrypi-firmware.h -@@ -9,6 +9,8 @@ - #include <linux/types.h> - #include <linux/of_device.h> - -+#define RPI_FIRMWARE_CHAN_FB 1 -+ - struct rpi_firmware; - - enum rpi_firmware_property_status { -@@ -73,6 +75,8 @@ enum rpi_firmware_property_tag { - RPI_FIRMWARE_GET_CUSTOMER_OTP = 0x00030021, - RPI_FIRMWARE_GET_DOMAIN_STATE = 0x00030030, - RPI_FIRMWARE_GET_THROTTLED = 0x00030046, -+ RPI_FIRMWARE_GET_CLOCK_MEASURED = 0x00030047, -+ RPI_FIRMWARE_NOTIFY_REBOOT = 0x00030048, - RPI_FIRMWARE_SET_CLOCK_STATE = 0x00038001, - RPI_FIRMWARE_SET_CLOCK_RATE = 0x00038002, - RPI_FIRMWARE_SET_VOLTAGE = 0x00038003, -@@ -155,5 +159,6 @@ static inline struct rpi_firmware *rpi_firmware_get(struct device_node *firmware - return NULL; - } - #endif -+int rpi_firmware_transaction(struct rpi_firmware *fw, u32 chan, u32 data); - - #endif /* __SOC_RASPBERRY_FIRMWARE_H__ */ diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0014-rtc-Add-SPI-alias-for-pcf2123-driver.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0014-rtc-Add-SPI-alias-for-pcf2123-driver.patch deleted file mode 100644 index 32cd3a04..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0014-rtc-Add-SPI-alias-for-pcf2123-driver.patch +++ /dev/null @@ -1,22 +0,0 @@ -From 39d4ad38a6ded4169160b15235131056c455d3c3 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Wed, 15 Jun 2016 16:48:41 +0100 -Subject: [PATCH 014/325] rtc: Add SPI alias for pcf2123 driver - -Without this alias, Device Tree won't cause the driver -to be loaded. - -See: https://github.com/raspberrypi/linux/pull/1510 ---- - drivers/rtc/rtc-pcf2123.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/rtc/rtc-pcf2123.c b/drivers/rtc/rtc-pcf2123.c -index 39da8b214275..849e1ccd97ab 100644 ---- a/drivers/rtc/rtc-pcf2123.c -+++ b/drivers/rtc/rtc-pcf2123.c -@@ -473,3 +473,4 @@ module_spi_driver(pcf2123_driver); - MODULE_AUTHOR("Chris Verges <chrisv@cyberswitching.com>"); - MODULE_DESCRIPTION("NXP PCF2123 RTC driver"); - MODULE_LICENSE("GPL"); -+MODULE_ALIAS("spi:rtc-pcf2123"); diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0015-watchdog-bcm2835-Support-setting-reboot-partition.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0015-watchdog-bcm2835-Support-setting-reboot-partition.patch deleted file mode 100644 index fe56244d..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0015-watchdog-bcm2835-Support-setting-reboot-partition.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 282fd2999745a11a4ad44a1cba78dfcafeb5a9b6 Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> -Date: Fri, 7 Oct 2016 16:50:59 +0200 -Subject: [PATCH 015/325] watchdog: bcm2835: Support setting reboot partition -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -The Raspberry Pi firmware looks at the RSTS register to know which -partition to boot from. The reboot syscall command -LINUX_REBOOT_CMD_RESTART2 supports passing in a string argument. - -Add support for passing in a partition number 0..63 to boot from. -Partition 63 is a special partiton indicating halt. -If the partition doesn't exist, the firmware falls back to partition 0. - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> ---- - drivers/watchdog/bcm2835_wdt.c | 49 +++++++++++++++++++--------------- - 1 file changed, 27 insertions(+), 22 deletions(-) - -diff --git a/drivers/watchdog/bcm2835_wdt.c b/drivers/watchdog/bcm2835_wdt.c -index ed05514cc2dc..9699e07119a7 100644 ---- a/drivers/watchdog/bcm2835_wdt.c -+++ b/drivers/watchdog/bcm2835_wdt.c -@@ -31,13 +31,7 @@ - #define PM_RSTC_WRCFG_SET 0x00000030 - #define PM_RSTC_WRCFG_FULL_RESET 0x00000020 - #define PM_RSTC_RESET 0x00000102 -- --/* -- * The Raspberry Pi firmware uses the RSTS register to know which partition -- * to boot from. The partition value is spread into bits 0, 2, 4, 6, 8, 10. -- * Partition 63 is a special partition used by the firmware to indicate halt. -- */ --#define PM_RSTS_RASPBERRYPI_HALT 0x555 -+#define PM_RSTS_PARTITION_CLR 0xfffffaaa - - #define SECS_TO_WDOG_TICKS(x) ((x) << 16) - #define WDOG_TICKS_TO_SECS(x) ((x) >> 16) -@@ -94,9 +88,24 @@ static unsigned int bcm2835_wdt_get_timeleft(struct watchdog_device *wdog) - return WDOG_TICKS_TO_SECS(ret & PM_WDOG_TIME_SET); - } - --static void __bcm2835_restart(struct bcm2835_wdt *wdt) -+/* -+ * The Raspberry Pi firmware uses the RSTS register to know which partiton -+ * to boot from. The partiton value is spread into bits 0, 2, 4, 6, 8, 10. -+ * Partiton 63 is a special partition used by the firmware to indicate halt. -+ */ -+ -+static void __bcm2835_restart(struct bcm2835_wdt *wdt, u8 partition) - { -- u32 val; -+ u32 val, rsts; -+ -+ rsts = (partition & BIT(0)) | ((partition & BIT(1)) << 1) | -+ ((partition & BIT(2)) << 2) | ((partition & BIT(3)) << 3) | -+ ((partition & BIT(4)) << 4) | ((partition & BIT(5)) << 5); -+ -+ val = readl_relaxed(wdt->base + PM_RSTS); -+ val &= PM_RSTS_PARTITION_CLR; -+ val |= PM_PASSWORD | rsts; -+ writel_relaxed(val, wdt->base + PM_RSTS); - - /* use a timeout of 10 ticks (~150us) */ - writel_relaxed(10 | PM_PASSWORD, wdt->base + PM_WDOG); -@@ -114,7 +123,13 @@ static int bcm2835_restart(struct watchdog_device *wdog, - { - struct bcm2835_wdt *wdt = watchdog_get_drvdata(wdog); - -- __bcm2835_restart(wdt); -+ unsigned long long val; -+ u8 partition = 0; -+ -+ if (data && !kstrtoull(data, 0, &val) && val <= 63) -+ partition = val; -+ -+ __bcm2835_restart(wdt, partition); - - return 0; - } -@@ -152,19 +167,9 @@ static void bcm2835_power_off(void) - of_find_compatible_node(NULL, NULL, "brcm,bcm2835-pm-wdt"); - struct platform_device *pdev = of_find_device_by_node(np); - struct bcm2835_wdt *wdt = platform_get_drvdata(pdev); -- u32 val; - -- /* -- * We set the watchdog hard reset bit here to distinguish this reset -- * from the normal (full) reset. bootcode.bin will not reboot after a -- * hard reset. -- */ -- val = readl_relaxed(wdt->base + PM_RSTS); -- val |= PM_PASSWORD | PM_RSTS_RASPBERRYPI_HALT; -- writel_relaxed(val, wdt->base + PM_RSTS); -- -- /* Continue with normal reset mechanism */ -- __bcm2835_restart(wdt); -+ /* Partition 63 tells the firmware that this is a halt */ -+ __bcm2835_restart(wdt, 63); - } - - static int bcm2835_wdt_probe(struct platform_device *pdev) diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0016-reboot-Use-power-off-rather-than-busy-spinning-when-.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0016-reboot-Use-power-off-rather-than-busy-spinning-when-.patch deleted file mode 100644 index 7e83c5ae..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0016-reboot-Use-power-off-rather-than-busy-spinning-when-.patch +++ /dev/null @@ -1,25 +0,0 @@ -From 3e3c7052b4a4da6b6096a7597d16c8ca7b556e11 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Tue, 5 Apr 2016 19:40:12 +0100 -Subject: [PATCH 016/325] reboot: Use power off rather than busy spinning when - halt is requested - ---- - arch/arm/kernel/reboot.c | 4 +--- - 1 file changed, 1 insertion(+), 3 deletions(-) - -diff --git a/arch/arm/kernel/reboot.c b/arch/arm/kernel/reboot.c -index 3b2aa9a9fe26..0180d89a34af 100644 ---- a/arch/arm/kernel/reboot.c -+++ b/arch/arm/kernel/reboot.c -@@ -105,9 +105,7 @@ void machine_shutdown(void) - */ - void machine_halt(void) - { -- local_irq_disable(); -- smp_send_stop(); -- while (1); -+ machine_power_off(); - } - - /* diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0017-bcm-Make-RASPBERRYPI_POWER-depend-on-PM.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0017-bcm-Make-RASPBERRYPI_POWER-depend-on-PM.patch deleted file mode 100644 index 56bec73f..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0017-bcm-Make-RASPBERRYPI_POWER-depend-on-PM.patch +++ /dev/null @@ -1,21 +0,0 @@ -From 921b4f237618c9ba1e5df3606a3b3205eb2c53ac Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Wed, 9 Nov 2016 13:02:52 +0000 -Subject: [PATCH 017/325] bcm: Make RASPBERRYPI_POWER depend on PM - ---- - drivers/soc/bcm/Kconfig | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/soc/bcm/Kconfig b/drivers/soc/bcm/Kconfig -index 055a845ed979..587c61998b72 100644 ---- a/drivers/soc/bcm/Kconfig -+++ b/drivers/soc/bcm/Kconfig -@@ -4,6 +4,7 @@ config RASPBERRYPI_POWER - bool "Raspberry Pi power domain driver" - depends on ARCH_BCM2835 || (COMPILE_TEST && OF) - depends on RASPBERRYPI_FIRMWARE=y -+ depends on PM - select PM_GENERIC_DOMAINS if PM - help - This enables support for the RPi power domains which can be enabled diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0018-Register-the-clocks-early-during-the-boot-process-so.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0018-Register-the-clocks-early-during-the-boot-process-so.patch deleted file mode 100644 index 33c2e393..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0018-Register-the-clocks-early-during-the-boot-process-so.patch +++ /dev/null @@ -1,47 +0,0 @@ -From 8dc8ad7009f731e73ea914465c765a13751bc9c9 Mon Sep 17 00:00:00 2001 -From: Martin Sperl <kernel@martin.sperl.org> -Date: Fri, 2 Sep 2016 16:45:27 +0100 -Subject: [PATCH 018/325] Register the clocks early during the boot process, so - that special/critical clocks can get enabled early on in the boot process - avoiding the risk of disabling a clock, pll_divider or pll when a claiming - driver fails to install propperly - maybe it needs to defer. - -Signed-off-by: Martin Sperl <kernel@martin.sperl.org> ---- - drivers/clk/bcm/clk-bcm2835.c | 15 +++++++++++++-- - 1 file changed, 13 insertions(+), 2 deletions(-) - -diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c -index 9fcae932e082..c8f6391127b5 100644 ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -2174,8 +2174,15 @@ static int bcm2835_clk_probe(struct platform_device *pdev) - if (ret) - return ret; - -- return of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, -+ ret = of_clk_add_hw_provider(dev->of_node, of_clk_hw_onecell_get, - &cprman->onecell); -+ if (ret) -+ return ret; -+ -+ /* note that we have registered all the clocks */ -+ dev_dbg(dev, "registered %d clocks\n", asize); -+ -+ return 0; - } - - static const struct of_device_id bcm2835_clk_of_match[] = { -@@ -2192,7 +2199,11 @@ static struct platform_driver bcm2835_clk_driver = { - .probe = bcm2835_clk_probe, - }; - --builtin_platform_driver(bcm2835_clk_driver); -+static int __init __bcm2835_clk_driver_init(void) -+{ -+ return platform_driver_register(&bcm2835_clk_driver); -+} -+core_initcall(__bcm2835_clk_driver_init); - - MODULE_AUTHOR("Eric Anholt <eric@anholt.net>"); - MODULE_DESCRIPTION("BCM2835 clock driver"); diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0019-bcm2835-rng-Avoid-initialising-if-already-enabled.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0019-bcm2835-rng-Avoid-initialising-if-already-enabled.patch deleted file mode 100644 index 0e310b09..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0019-bcm2835-rng-Avoid-initialising-if-already-enabled.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 0532efb05ad84d0dea940186e021bec4ef66f32e Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Tue, 6 Dec 2016 17:05:39 +0000 -Subject: [PATCH 019/325] bcm2835-rng: Avoid initialising if already enabled - -Avoids the 0x40000 cycles of warmup again if firmware has already used it ---- - drivers/char/hw_random/bcm2835-rng.c | 6 ++++-- - 1 file changed, 4 insertions(+), 2 deletions(-) - -diff --git a/drivers/char/hw_random/bcm2835-rng.c b/drivers/char/hw_random/bcm2835-rng.c -index 256b0b1d0f26..cc4bcbd76b35 100644 ---- a/drivers/char/hw_random/bcm2835-rng.c -+++ b/drivers/char/hw_random/bcm2835-rng.c -@@ -102,8 +102,10 @@ static int bcm2835_rng_init(struct hwrng *rng) - } - - /* set warm-up count & enable */ -- rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS); -- rng_writel(priv, RNG_RBGEN, RNG_CTRL); -+ if (!(rng_readl(priv, RNG_CTRL) & RNG_RBGEN)) { -+ rng_writel(priv, RNG_WARMUP_COUNT, RNG_STATUS); -+ rng_writel(priv, RNG_RBGEN, RNG_CTRL); -+ } - - return ret; - } diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0020-clk-bcm2835-Mark-used-PLLs-and-dividers-CRITICAL.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0020-clk-bcm2835-Mark-used-PLLs-and-dividers-CRITICAL.patch deleted file mode 100644 index eec9e20c..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0020-clk-bcm2835-Mark-used-PLLs-and-dividers-CRITICAL.patch +++ /dev/null @@ -1,30 +0,0 @@ -From c88a52f565d5d2e353bcf85f612a4024686e8fce Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Mon, 13 Feb 2017 17:20:08 +0000 -Subject: [PATCH 020/325] clk-bcm2835: Mark used PLLs and dividers CRITICAL - -The VPU configures and relies on several PLLs and dividers. Mark all -enabled dividers and their PLLs as CRITICAL to prevent the kernel from -switching them off. - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - drivers/clk/bcm/clk-bcm2835.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c -index c8f6391127b5..0372f26540d6 100644 ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -1352,6 +1352,11 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, - divider->div.hw.init = &init; - divider->div.table = NULL; - -+ if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) { -+ init.flags |= CLK_IS_CRITICAL; -+ divider->div.flags |= CLK_IS_CRITICAL; -+ } -+ - divider->cprman = cprman; - divider->data = data; - diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0021-clk-bcm2835-Add-claim-clocks-property.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0021-clk-bcm2835-Add-claim-clocks-property.patch deleted file mode 100644 index b204533e..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0021-clk-bcm2835-Add-claim-clocks-property.patch +++ /dev/null @@ -1,104 +0,0 @@ -From 940c0d652e42793db245667fc3357a8edb08cac6 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Mon, 13 Feb 2017 17:20:08 +0000 -Subject: [PATCH 021/325] clk-bcm2835: Add claim-clocks property - -The claim-clocks property can be used to prevent PLLs and dividers -from being marked as critical. It contains a vector of clock IDs, -as defined by dt-bindings/clock/bcm2835.h. - -Use this mechanism to claim PLLD_DSI0, PLLD_DSI1, PLLH_AUX and -PLLH_PIX for the vc4_kms_v3d driver. - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - drivers/clk/bcm/clk-bcm2835.c | 34 ++++++++++++++++++++++++++++++++-- - 1 file changed, 32 insertions(+), 2 deletions(-) - -diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c -index 0372f26540d6..fd381f8f43f7 100644 ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -1284,6 +1284,8 @@ static const struct clk_ops bcm2835_vpu_clock_clk_ops = { - .debug_init = bcm2835_clock_debug_init, - }; - -+static bool bcm2835_clk_is_claimed(const char *name); -+ - static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, - const struct bcm2835_pll_data *data) - { -@@ -1300,6 +1302,9 @@ static struct clk_hw *bcm2835_register_pll(struct bcm2835_cprman *cprman, - init.ops = &bcm2835_pll_clk_ops; - init.flags = CLK_IGNORE_UNUSED; - -+ if (!bcm2835_clk_is_claimed(data->name)) -+ init.flags |= CLK_IS_CRITICAL; -+ - pll = kzalloc(sizeof(*pll), GFP_KERNEL); - if (!pll) - return NULL; -@@ -1353,8 +1358,10 @@ bcm2835_register_pll_divider(struct bcm2835_cprman *cprman, - divider->div.table = NULL; - - if (!(cprman_read(cprman, data->cm_reg) & data->hold_mask)) { -- init.flags |= CLK_IS_CRITICAL; -- divider->div.flags |= CLK_IS_CRITICAL; -+ if (!bcm2835_clk_is_claimed(data->source_pll)) -+ init.flags |= CLK_IS_CRITICAL; -+ if (!bcm2835_clk_is_claimed(data->name)) -+ divider->div.flags |= CLK_IS_CRITICAL; - } - - divider->cprman = cprman; -@@ -2106,6 +2113,8 @@ static const struct bcm2835_clk_desc clk_desc_array[] = { - .ctl_reg = CM_PERIICTL), - }; - -+static bool bcm2835_clk_claimed[ARRAY_SIZE(clk_desc_array)]; -+ - /* - * Permanently take a reference on the parent of the SDRAM clock. - * -@@ -2125,6 +2134,19 @@ static int bcm2835_mark_sdc_parent_critical(struct clk *sdc) - return clk_prepare_enable(parent); - } - -+static bool bcm2835_clk_is_claimed(const char *name) -+{ -+ int i; -+ -+ for (i = 0; i < ARRAY_SIZE(clk_desc_array); i++) { -+ const char *clk_name = *(const char **)(clk_desc_array[i].data); -+ if (!strcmp(name, clk_name)) -+ return bcm2835_clk_claimed[i]; -+ } -+ -+ return false; -+} -+ - static int bcm2835_clk_probe(struct platform_device *pdev) - { - struct device *dev = &pdev->dev; -@@ -2134,6 +2156,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev) - const struct bcm2835_clk_desc *desc; - const size_t asize = ARRAY_SIZE(clk_desc_array); - size_t i; -+ u32 clk_id; - int ret; - - cprman = devm_kzalloc(dev, -@@ -2149,6 +2172,13 @@ static int bcm2835_clk_probe(struct platform_device *pdev) - if (IS_ERR(cprman->regs)) - return PTR_ERR(cprman->regs); - -+ memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed)); -+ for (i = 0; -+ !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks", -+ i, &clk_id); -+ i++) -+ bcm2835_clk_claimed[clk_id]= true; -+ - memcpy(cprman->real_parent_names, cprman_parent_names, - sizeof(cprman_parent_names)); - of_clk_parent_fill(dev->of_node, cprman->real_parent_names, diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0022-clk-bcm2835-Read-max-core-clock-from-firmware.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0022-clk-bcm2835-Read-max-core-clock-from-firmware.patch deleted file mode 100644 index 9e4db283..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0022-clk-bcm2835-Read-max-core-clock-from-firmware.patch +++ /dev/null @@ -1,117 +0,0 @@ -From a1fd96f08470318b72bff6de240a796cdf96e342 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Mon, 6 Mar 2017 09:06:18 +0000 -Subject: [PATCH 022/325] clk-bcm2835: Read max core clock from firmware - -The VPU is responsible for managing the core clock, usually under -direction from the bcm2835-cpufreq driver but not via the clk-bcm2835 -driver. Since the core frequency can change without warning, it is -safer to report the maximum clock rate to users of the core clock - -I2C, SPI and the mini UART - to err on the safe side when calculating -clock divisors. - -If the DT node for the clock driver includes a reference to the -firmware node, use the firmware API to query the maximum core clock -instead of reading the divider registers. - -Prior to this patch, a "100KHz" I2C bus was sometimes clocked at about -160KHz. In particular, switching to the 4.9 kernel was likely to break -SenseHAT usage on a Pi3. - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - drivers/clk/bcm/clk-bcm2835.c | 39 ++++++++++++++++++++++++++++++++++- - 1 file changed, 38 insertions(+), 1 deletion(-) - -diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c -index fd381f8f43f7..e1ceafdc7dce 100644 ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -34,6 +34,7 @@ - #include <linux/platform_device.h> - #include <linux/slab.h> - #include <dt-bindings/clock/bcm2835.h> -+#include <soc/bcm2835/raspberrypi-firmware.h> - - #define CM_PASSWORD 0x5a000000 - -@@ -288,6 +289,8 @@ - #define LOCK_TIMEOUT_NS 100000000 - #define BCM2835_MAX_FB_RATE 1750000000u - -+#define VCMSG_ID_CORE_CLOCK 4 -+ - /* - * Names of clocks used within the driver that need to be replaced - * with an external parent's name. This array is in the order that -@@ -306,6 +309,7 @@ static const char *const cprman_parent_names[] = { - struct bcm2835_cprman { - struct device *dev; - void __iomem *regs; -+ struct rpi_firmware *fw; - spinlock_t regs_lock; /* spinlock for all clocks */ - - /* -@@ -988,6 +992,30 @@ static unsigned long bcm2835_clock_get_rate(struct clk_hw *hw, - return bcm2835_clock_rate_from_divisor(clock, parent_rate, div); - } - -+static unsigned long bcm2835_clock_get_rate_vpu(struct clk_hw *hw, -+ unsigned long parent_rate) -+{ -+ struct bcm2835_clock *clock = bcm2835_clock_from_hw(hw); -+ struct bcm2835_cprman *cprman = clock->cprman; -+ -+ if (cprman->fw) { -+ struct { -+ u32 id; -+ u32 val; -+ } packet; -+ -+ packet.id = VCMSG_ID_CORE_CLOCK; -+ packet.val = 0; -+ -+ if (!rpi_firmware_property(cprman->fw, -+ RPI_FIRMWARE_GET_MAX_CLOCK_RATE, -+ &packet, sizeof(packet))) -+ return packet.val; -+ } -+ -+ return bcm2835_clock_get_rate(hw, parent_rate); -+} -+ - static void bcm2835_clock_wait_busy(struct bcm2835_clock *clock) - { - struct bcm2835_cprman *cprman = clock->cprman; -@@ -1276,7 +1304,7 @@ static int bcm2835_vpu_clock_is_on(struct clk_hw *hw) - */ - static const struct clk_ops bcm2835_vpu_clock_clk_ops = { - .is_prepared = bcm2835_vpu_clock_is_on, -- .recalc_rate = bcm2835_clock_get_rate, -+ .recalc_rate = bcm2835_clock_get_rate_vpu, - .set_rate = bcm2835_clock_set_rate, - .determine_rate = bcm2835_clock_determine_rate, - .set_parent = bcm2835_clock_set_parent, -@@ -2155,6 +2183,7 @@ static int bcm2835_clk_probe(struct platform_device *pdev) - struct resource *res; - const struct bcm2835_clk_desc *desc; - const size_t asize = ARRAY_SIZE(clk_desc_array); -+ struct device_node *fw_node; - size_t i; - u32 clk_id; - int ret; -@@ -2172,6 +2201,14 @@ static int bcm2835_clk_probe(struct platform_device *pdev) - if (IS_ERR(cprman->regs)) - return PTR_ERR(cprman->regs); - -+ fw_node = of_parse_phandle(dev->of_node, "firmware", 0); -+ if (fw_node) { -+ struct rpi_firmware *fw = rpi_firmware_get(NULL); -+ if (!fw) -+ return -EPROBE_DEFER; -+ cprman->fw = fw; -+ } -+ - memset(bcm2835_clk_claimed, 0, sizeof(bcm2835_clk_claimed)); - for (i = 0; - !of_property_read_u32_index(pdev->dev.of_node, "claim-clocks", diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0023-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0023-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch deleted file mode 100644 index 55c5fa4f..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0023-clk-bcm2835-Mark-GPIO-clocks-enabled-at-boot-as-crit.patch +++ /dev/null @@ -1,40 +0,0 @@ -From 402e6bd22be8e645624f0b9b38ffcc574ca665cc Mon Sep 17 00:00:00 2001 -From: Eric Anholt <eric@anholt.net> -Date: Mon, 9 May 2016 17:28:18 -0700 -Subject: [PATCH 023/325] clk: bcm2835: Mark GPIO clocks enabled at boot as - critical. - -These divide off of PLLD_PER and are used for the ethernet and wifi -PHYs source PLLs. Neither of them is currently represented by a phy -device that would grab the clock for us. - -This keeps other drivers from killing the networking PHYs when they -disable their own clocks and trigger PLLD_PER's refcount going to 0. - -v2: Skip marking as critical if they aren't on at boot. - -Signed-off-by: Eric Anholt <eric@anholt.net> ---- - drivers/clk/bcm/clk-bcm2835.c | 9 +++++++++ - 1 file changed, 9 insertions(+) - -diff --git a/drivers/clk/bcm/clk-bcm2835.c b/drivers/clk/bcm/clk-bcm2835.c -index e1ceafdc7dce..b6399a4fc53f 100644 ---- a/drivers/clk/bcm/clk-bcm2835.c -+++ b/drivers/clk/bcm/clk-bcm2835.c -@@ -1443,6 +1443,15 @@ static struct clk_hw *bcm2835_register_clock(struct bcm2835_cprman *cprman, - init.name = data->name; - init.flags = data->flags | CLK_IGNORE_UNUSED; - -+ /* -+ * Some GPIO clocks for ethernet/wifi PLLs are marked as -+ * critical (since some platforms use them), but if the -+ * firmware didn't have them turned on then they clearly -+ * aren't actually critical. -+ */ -+ if ((cprman_read(cprman, data->ctl_reg) & CM_ENABLE) == 0) -+ init.flags &= ~CLK_IS_CRITICAL; -+ - /* - * Pass the CLK_SET_RATE_PARENT flag if we are allowed to propagate - * rate changes on at least of the parents. diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0024-sound-Demote-deferral-errors-to-INFO-level.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0024-sound-Demote-deferral-errors-to-INFO-level.patch deleted file mode 100644 index 381f02b9..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0024-sound-Demote-deferral-errors-to-INFO-level.patch +++ /dev/null @@ -1,39 +0,0 @@ -From 89d961225324dbf2c768e42f2c2f7d1f3a202f02 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Thu, 9 Feb 2017 14:36:44 +0000 -Subject: [PATCH 024/325] sound: Demote deferral errors to INFO level - -At present there is no mechanism to specify driver load order, -which can lead to deferrals and repeated retries until successful. -Since this situation is expected, reduce the dmesg level to -INFO and mention that the operation will be retried. - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - sound/soc/soc-core.c | 6 +++--- - 1 file changed, 3 insertions(+), 3 deletions(-) - -diff --git a/sound/soc/soc-core.c b/sound/soc/soc-core.c -index 416c371fa01a..c0d2b33a618b 100644 ---- a/sound/soc/soc-core.c -+++ b/sound/soc/soc-core.c -@@ -894,8 +894,8 @@ static int soc_bind_dai_link(struct snd_soc_card *card, - cpu_dai_component.dai_name = dai_link->cpu_dai_name; - rtd->cpu_dai = snd_soc_find_dai(&cpu_dai_component); - if (!rtd->cpu_dai) { -- dev_info(card->dev, "ASoC: CPU DAI %s not registered\n", -- dai_link->cpu_dai_name); -+ dev_info(card->dev, "ASoC: CPU DAI %s not registered - will retry\n", -+ dai_link->cpu_dai_name); - goto _err_defer; - } - snd_soc_rtdcom_add(rtd, rtd->cpu_dai->component); -@@ -908,7 +908,7 @@ static int soc_bind_dai_link(struct snd_soc_card *card, - for (i = 0; i < rtd->num_codecs; i++) { - codec_dais[i] = snd_soc_find_dai(&codecs[i]); - if (!codec_dais[i]) { -- dev_err(card->dev, "ASoC: CODEC DAI %s not registered\n", -+ dev_info(card->dev, "ASoC: CODEC DAI %s not registered - will retry\n", - codecs[i].dai_name); - goto _err_defer; - } diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0025-Update-vfpmodule.c.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0025-Update-vfpmodule.c.patch deleted file mode 100644 index 2cebf109..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0025-Update-vfpmodule.c.patch +++ /dev/null @@ -1,139 +0,0 @@ -From 3cbab2774b9b8959085716296d51b80fa9b919db Mon Sep 17 00:00:00 2001 -From: Claggy3 <stephen.maclagan@hotmail.com> -Date: Sat, 11 Feb 2017 14:00:30 +0000 -Subject: [PATCH 025/325] Update vfpmodule.c - -Christopher Alexander Tobias Schulze - May 2, 2015, 11:57 a.m. -This patch fixes a problem with VFP state save and restore related -to exception handling (panic with message "BUG: unsupported FP -instruction in kernel mode") present on VFP11 floating point units -(as used with ARM1176JZF-S CPUs, e.g. on first generation Raspberry -Pi boards). This patch was developed and discussed on - - https://github.com/raspberrypi/linux/issues/859 - -A precondition to see the crashes is that floating point exception -traps are enabled. In this case, the VFP11 might determine that a FPU -operation needs to trap at a point in time when it is not possible to -signal this to the ARM11 core any more. The VFP11 will then set the -FPEXC.EX bit and store the trapped opcode in FPINST. (In some cases, -a second opcode might have been accepted by the VFP11 before the -exception was detected and could be reported to the ARM11 - in this -case, the VFP11 also sets FPEXC.FP2V and stores the second opcode in -FPINST2.) - -If FPEXC.EX is set, the VFP11 will "bounce" the next FPU opcode issued -by the ARM11 CPU, which will be seen by the ARM11 as an undefined opcode -trap. The VFP support code examines the FPEXC.EX and FPEXC.FP2V bits -to decide what actions to take, i.e., whether to emulate the opcodes -found in FPINST and FPINST2, and whether to retry the bounced instruction. - -If a user space application has left the VFP11 in this "pending trap" -state, the next FPU opcode issued to the VFP11 might actually be the -VSTMIA operation vfp_save_state() uses to store the FPU registers -to memory (in our test cases, when building the signal stack frame). -In this case, the kernel crashes as described above. - -This patch fixes the problem by making sure that vfp_save_state() is -always entered with FPEXC.EX cleared. (The current value of FPEXC has -already been saved, so this does not corrupt the context. Clearing -FPEXC.EX has no effects on FPINST or FPINST2. Also note that many -callers already modify FPEXC by setting FPEXC.EN before invoking -vfp_save_state().) - -This patch also addresses a second problem related to FPEXC.EX: After -returning from signal handling, the kernel reloads the VFP context -from the user mode stack. However, the current code explicitly clears -both FPEXC.EX and FPEXC.FP2V during reload. As VFP11 requires these -bits to be preserved, this patch disables clearing them for VFP -implementations belonging to architecture 1. There should be no -negative side effects: the user can set both bits by executing FPU -opcodes anyway, and while user code may now place arbitrary values -into FPINST and FPINST2 (e.g., non-VFP ARM opcodes) the VFP support -code knows which instructions can be emulated, and rejects other -opcodes with "unhandled bounce" messages, so there should be no -security impact from allowing reloading FPEXC.EX and FPEXC.FP2V. - -Signed-off-by: Christopher Alexander Tobias Schulze <cat.schulze@alice-dsl.net> ---- - arch/arm/vfp/vfpmodule.c | 25 +++++++++++++++++++------ - 1 file changed, 19 insertions(+), 6 deletions(-) - -diff --git a/arch/arm/vfp/vfpmodule.c b/arch/arm/vfp/vfpmodule.c -index ee7b07938dd5..ad4398dcca27 100644 ---- a/arch/arm/vfp/vfpmodule.c -+++ b/arch/arm/vfp/vfpmodule.c -@@ -179,8 +179,11 @@ static int vfp_notifier(struct notifier_block *self, unsigned long cmd, void *v) - * case the thread migrates to a different CPU. The - * restoring is done lazily. - */ -- if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) -+ if ((fpexc & FPEXC_EN) && vfp_current_hw_state[cpu]) { -+ /* vfp_save_state oopses on VFP11 if EX bit set */ -+ fmxr(FPEXC, fpexc & ~FPEXC_EX); - vfp_save_state(vfp_current_hw_state[cpu], fpexc); -+ } - #endif - - /* -@@ -457,13 +460,16 @@ static int vfp_pm_suspend(void) - /* if vfp is on, then save state for resumption */ - if (fpexc & FPEXC_EN) { - pr_debug("%s: saving vfp state\n", __func__); -+ /* vfp_save_state oopses on VFP11 if EX bit set */ -+ fmxr(FPEXC, fpexc & ~FPEXC_EX); - vfp_save_state(&ti->vfpstate, fpexc); - - /* disable, just in case */ - fmxr(FPEXC, fmrx(FPEXC) & ~FPEXC_EN); - } else if (vfp_current_hw_state[ti->cpu]) { - #ifndef CONFIG_SMP -- fmxr(FPEXC, fpexc | FPEXC_EN); -+ /* vfp_save_state oopses on VFP11 if EX bit set */ -+ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN); - vfp_save_state(vfp_current_hw_state[ti->cpu], fpexc); - fmxr(FPEXC, fpexc); - #endif -@@ -526,7 +532,8 @@ void vfp_sync_hwstate(struct thread_info *thread) - /* - * Save the last VFP state on this CPU. - */ -- fmxr(FPEXC, fpexc | FPEXC_EN); -+ /* vfp_save_state oopses on VFP11 if EX bit set */ -+ fmxr(FPEXC, (fpexc & ~FPEXC_EX) | FPEXC_EN); - vfp_save_state(&thread->vfpstate, fpexc | FPEXC_EN); - fmxr(FPEXC, fpexc); - } -@@ -592,6 +599,7 @@ int vfp_restore_user_hwstate(struct user_vfp *ufp, struct user_vfp_exc *ufp_exc) - struct thread_info *thread = current_thread_info(); - struct vfp_hard_struct *hwstate = &thread->vfpstate.hard; - unsigned long fpexc; -+ u32 fpsid = fmrx(FPSID); - - /* Disable VFP to avoid corrupting the new thread state. */ - vfp_flush_hwstate(thread); -@@ -614,8 +622,12 @@ int vfp_restore_user_hwstate(struct user_vfp *ufp, struct user_vfp_exc *ufp_exc) - /* Ensure the VFP is enabled. */ - fpexc |= FPEXC_EN; - -- /* Ensure FPINST2 is invalid and the exception flag is cleared. */ -- fpexc &= ~(FPEXC_EX | FPEXC_FP2V); -+ /* Mask FPXEC_EX and FPEXC_FP2V if not required by VFP arch */ -+ if ((fpsid & FPSID_ARCH_MASK) != (1 << FPSID_ARCH_BIT)) { -+ /* Ensure FPINST2 is invalid and the exception flag is cleared. */ -+ fpexc &= ~(FPEXC_EX | FPEXC_FP2V); -+ } -+ - hwstate->fpexc = fpexc; - - hwstate->fpinst = ufp_exc->fpinst; -@@ -685,7 +697,8 @@ void kernel_neon_begin(void) - cpu = get_cpu(); - - fpexc = fmrx(FPEXC) | FPEXC_EN; -- fmxr(FPEXC, fpexc); -+ /* vfp_save_state oopses on VFP11 if EX bit set */ -+ fmxr(FPEXC, fpexc & ~FPEXC_EX); - - /* - * Save the userland NEON/VFP state. Under UP, diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0026-i2c-bcm2835-Add-debug-support.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0026-i2c-bcm2835-Add-debug-support.patch deleted file mode 100644 index 0be439ae..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0026-i2c-bcm2835-Add-debug-support.patch +++ /dev/null @@ -1,191 +0,0 @@ -From 50d69580b63ab04c8a86331fd292fc25a8c47abb Mon Sep 17 00:00:00 2001 -From: =?UTF-8?q?Noralf=20Tr=C3=B8nnes?= <noralf@tronnes.org> -Date: Tue, 1 Nov 2016 15:15:41 +0100 -Subject: [PATCH 026/325] i2c: bcm2835: Add debug support -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -This adds a debug module parameter to aid in debugging transfer issues -by printing info to the kernel log. When enabled, status values are -collected in the interrupt routine and msg info in -bcm2835_i2c_start_transfer(). This is done in a way that tries to avoid -affecting timing. Having printk in the isr can mask issues. - -debug values (additive): -1: Print info on error -2: Print info on all transfers -3: Print messages before transfer is started - -The value can be changed at runtime: -/sys/module/i2c_bcm2835/parameters/debug - -Example output, debug=3: -[ 747.114448] bcm2835_i2c_xfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1] -[ 747.114463] bcm2835_i2c_xfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1] -[ 747.117809] start_transfer: msg(1/2) write addr=0x54, len=2 flags= [i2c1] -[ 747.117825] isr: remain=2, status=0x30000055 : TA TXW TXD TXE [i2c1] -[ 747.117839] start_transfer: msg(2/2) read addr=0x54, len=32 flags= [i2c1] -[ 747.117849] isr: remain=32, status=0xd0000039 : TA RXR TXD RXD [i2c1] -[ 747.117861] isr: remain=20, status=0xd0000039 : TA RXR TXD RXD [i2c1] -[ 747.117870] isr: remain=8, status=0x32 : DONE TXD RXD [i2c1] - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> ---- - drivers/i2c/busses/i2c-bcm2835.c | 99 +++++++++++++++++++++++++++++++- - 1 file changed, 98 insertions(+), 1 deletion(-) - -diff --git a/drivers/i2c/busses/i2c-bcm2835.c b/drivers/i2c/busses/i2c-bcm2835.c -index d2fbb4bb4a43..da8d409122c1 100644 ---- a/drivers/i2c/busses/i2c-bcm2835.c -+++ b/drivers/i2c/busses/i2c-bcm2835.c -@@ -48,6 +48,18 @@ - #define BCM2835_I2C_CDIV_MIN 0x0002 - #define BCM2835_I2C_CDIV_MAX 0xFFFE - -+static unsigned int debug; -+module_param(debug, uint, 0644); -+MODULE_PARM_DESC(debug, "1=err, 2=isr, 3=xfer"); -+ -+#define BCM2835_DEBUG_MAX 512 -+struct bcm2835_debug { -+ struct i2c_msg *msg; -+ int msg_idx; -+ size_t remain; -+ u32 status; -+}; -+ - struct bcm2835_i2c_dev { - struct device *dev; - void __iomem *regs; -@@ -61,8 +73,78 @@ struct bcm2835_i2c_dev { - u32 msg_err; - u8 *msg_buf; - size_t msg_buf_remaining; -+ struct bcm2835_debug debug[BCM2835_DEBUG_MAX]; -+ unsigned int debug_num; -+ unsigned int debug_num_msgs; - }; - -+static inline void bcm2835_debug_add(struct bcm2835_i2c_dev *i2c_dev, u32 s) -+{ -+ if (!i2c_dev->debug_num_msgs || i2c_dev->debug_num >= BCM2835_DEBUG_MAX) -+ return; -+ -+ i2c_dev->debug[i2c_dev->debug_num].msg = i2c_dev->curr_msg; -+ i2c_dev->debug[i2c_dev->debug_num].msg_idx = -+ i2c_dev->debug_num_msgs - i2c_dev->num_msgs; -+ i2c_dev->debug[i2c_dev->debug_num].remain = i2c_dev->msg_buf_remaining; -+ i2c_dev->debug[i2c_dev->debug_num].status = s; -+ i2c_dev->debug_num++; -+} -+ -+static void bcm2835_debug_print_status(struct bcm2835_i2c_dev *i2c_dev, -+ struct bcm2835_debug *d) -+{ -+ u32 s = d->status; -+ -+ pr_info("isr: remain=%zu, status=0x%x : %s%s%s%s%s%s%s%s%s%s [i2c%d]\n", -+ d->remain, s, -+ s & BCM2835_I2C_S_TA ? "TA " : "", -+ s & BCM2835_I2C_S_DONE ? "DONE " : "", -+ s & BCM2835_I2C_S_TXW ? "TXW " : "", -+ s & BCM2835_I2C_S_RXR ? "RXR " : "", -+ s & BCM2835_I2C_S_TXD ? "TXD " : "", -+ s & BCM2835_I2C_S_RXD ? "RXD " : "", -+ s & BCM2835_I2C_S_TXE ? "TXE " : "", -+ s & BCM2835_I2C_S_RXF ? "RXF " : "", -+ s & BCM2835_I2C_S_ERR ? "ERR " : "", -+ s & BCM2835_I2C_S_CLKT ? "CLKT " : "", -+ i2c_dev->adapter.nr); -+} -+ -+static void bcm2835_debug_print_msg(struct bcm2835_i2c_dev *i2c_dev, -+ struct i2c_msg *msg, int i, int total, -+ const char *fname) -+{ -+ pr_info("%s: msg(%d/%d) %s addr=0x%02x, len=%u flags=%s%s%s%s%s%s%s [i2c%d]\n", -+ fname, i, total, -+ msg->flags & I2C_M_RD ? "read" : "write", msg->addr, msg->len, -+ msg->flags & I2C_M_TEN ? "TEN" : "", -+ msg->flags & I2C_M_RECV_LEN ? "RECV_LEN" : "", -+ msg->flags & I2C_M_NO_RD_ACK ? "NO_RD_ACK" : "", -+ msg->flags & I2C_M_IGNORE_NAK ? "IGNORE_NAK" : "", -+ msg->flags & I2C_M_REV_DIR_ADDR ? "REV_DIR_ADDR" : "", -+ msg->flags & I2C_M_NOSTART ? "NOSTART" : "", -+ msg->flags & I2C_M_STOP ? "STOP" : "", -+ i2c_dev->adapter.nr); -+} -+ -+static void bcm2835_debug_print(struct bcm2835_i2c_dev *i2c_dev) -+{ -+ struct bcm2835_debug *d; -+ unsigned int i; -+ -+ for (i = 0; i < i2c_dev->debug_num; i++) { -+ d = &i2c_dev->debug[i]; -+ if (d->status == ~0) -+ bcm2835_debug_print_msg(i2c_dev, d->msg, d->msg_idx, -+ i2c_dev->debug_num_msgs, "start_transfer"); -+ else -+ bcm2835_debug_print_status(i2c_dev, d); -+ } -+ if (i2c_dev->debug_num >= BCM2835_DEBUG_MAX) -+ pr_info("BCM2835_DEBUG_MAX reached\n"); -+} -+ - static inline void bcm2835_i2c_writel(struct bcm2835_i2c_dev *i2c_dev, - u32 reg, u32 val) - { -@@ -181,6 +263,7 @@ static void bcm2835_i2c_start_transfer(struct bcm2835_i2c_dev *i2c_dev) - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_A, msg->addr); - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_DLEN, msg->len); - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, c); -+ bcm2835_debug_add(i2c_dev, ~0); - } - - static void bcm2835_i2c_finish_transfer(struct bcm2835_i2c_dev *i2c_dev) -@@ -207,6 +290,7 @@ static irqreturn_t bcm2835_i2c_isr(int this_irq, void *data) - u32 val, err; - - val = bcm2835_i2c_readl(i2c_dev, BCM2835_I2C_S); -+ bcm2835_debug_add(i2c_dev, val); - - err = val & (BCM2835_I2C_S_CLKT | BCM2835_I2C_S_ERR); - if (err) { -@@ -273,6 +357,13 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], - unsigned long time_left; - int i, ret; - -+ if (debug) -+ i2c_dev->debug_num_msgs = num; -+ -+ if (debug > 2) -+ for (i = 0; i < num; i++) -+ bcm2835_debug_print_msg(i2c_dev, &msgs[i], i + 1, num, __func__); -+ - for (i = 0; i < (num - 1); i++) - if (msgs[i].flags & I2C_M_RD) { - dev_warn_once(i2c_dev->dev, -@@ -295,6 +386,10 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], - - bcm2835_i2c_finish_transfer(i2c_dev); - -+ if (debug > 1 || (debug && (!time_left || i2c_dev->msg_err))) -+ bcm2835_debug_print(i2c_dev); -+ i2c_dev->debug_num_msgs = 0; -+ i2c_dev->debug_num = 0; - if (!time_left) { - bcm2835_i2c_writel(i2c_dev, BCM2835_I2C_C, - BCM2835_I2C_C_CLEAR); -@@ -305,7 +400,9 @@ static int bcm2835_i2c_xfer(struct i2c_adapter *adap, struct i2c_msg msgs[], - if (!i2c_dev->msg_err) - return num; - -- dev_dbg(i2c_dev->dev, "i2c transfer failed: %x\n", i2c_dev->msg_err); -+ if (debug) -+ dev_err(i2c_dev->dev, "i2c transfer failed: %x\n", -+ i2c_dev->msg_err); - - if (i2c_dev->msg_err & BCM2835_I2C_S_ERR) - return -EREMOTEIO; diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0027-mm-Remove-the-PFN-busy-warning.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0027-mm-Remove-the-PFN-busy-warning.patch deleted file mode 100644 index 6c78180c..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0027-mm-Remove-the-PFN-busy-warning.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 11c4c75b0f34c91f41b32eba626fe8f8ca232aa9 Mon Sep 17 00:00:00 2001 -From: Eric Anholt <eric@anholt.net> -Date: Thu, 18 Dec 2014 16:07:15 -0800 -Subject: [PATCH 027/325] mm: Remove the PFN busy warning - -See commit dae803e165a11bc88ca8dbc07a11077caf97bbcb -- the warning is -expected sometimes when using CMA. However, that commit still spams -my kernel log with these warnings. - -Signed-off-by: Eric Anholt <eric@anholt.net> ---- - mm/page_alloc.c | 2 -- - 1 file changed, 2 deletions(-) - -diff --git a/mm/page_alloc.c b/mm/page_alloc.c -index d59be95ba45c..a08e8af01a3f 100644 ---- a/mm/page_alloc.c -+++ b/mm/page_alloc.c -@@ -8245,8 +8245,6 @@ int alloc_contig_range(unsigned long start, unsigned long end, - - /* Make sure the range is really isolated. */ - if (test_pages_isolated(outer_start, end, false)) { -- pr_info_ratelimited("%s: [%lx, %lx) PFNs busy\n", -- __func__, outer_start, end); - ret = -EBUSY; - goto done; - } diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0028-ASoC-Add-prompt-for-ICS43432-codec.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0028-ASoC-Add-prompt-for-ICS43432-codec.patch deleted file mode 100644 index 5027f3aa..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0028-ASoC-Add-prompt-for-ICS43432-codec.patch +++ /dev/null @@ -1,27 +0,0 @@ -From 791598b9fd8669068bb96e5d6e5fe31abf518e22 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Thu, 23 Mar 2017 10:06:56 +0000 -Subject: [PATCH 028/325] ASoC: Add prompt for ICS43432 codec - -Without a prompt string, a config setting can't be included in a -defconfig. Give CONFIG_SND_SOC_ICS43432 a prompt so that Pi soundcards -can use the driver. - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - sound/soc/codecs/Kconfig | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/sound/soc/codecs/Kconfig b/sound/soc/codecs/Kconfig -index 62bdb7e333b8..63e86416e4f7 100644 ---- a/sound/soc/codecs/Kconfig -+++ b/sound/soc/codecs/Kconfig -@@ -634,7 +634,7 @@ config SND_SOC_HDAC_HDA - select SND_HDA - - config SND_SOC_ICS43432 -- tristate -+ tristate "InvenSense ICS43432 I2S microphone codec" - - config SND_SOC_INNO_RK3036 - tristate "Inno codec driver for RK3036 SoC" diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0029-irqchip-irq-bcm2836-Remove-regmap-and-syscon-use.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0029-irqchip-irq-bcm2836-Remove-regmap-and-syscon-use.patch deleted file mode 100644 index 2563c1c3..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0029-irqchip-irq-bcm2836-Remove-regmap-and-syscon-use.patch +++ /dev/null @@ -1,116 +0,0 @@ -From a747c094f3bfb3aec91a5e28d8c8af128ce2e243 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Tue, 23 Jan 2018 16:52:45 +0000 -Subject: [PATCH 029/325] irqchip: irq-bcm2836: Remove regmap and syscon use - -The syscon node defines a register range that duplicates that used by -the local_intc node on bcm2836/7. Since irq-bcm2835 and irq-bcm2836 are -built in and always present together (both drivers are enabled by -CONFIG_ARCH_BCM2835), it is possible to replace the syscon usage with a -global variable that simplifies the code. Doing so does lose the -locking provided by regmap, but as only one side is using the regmap -interface (irq-bcm2835 uses readl and write) there is no loss of -atomicity. - -See: https://github.com/raspberrypi/firmware/issues/926 - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - drivers/irqchip/irq-bcm2835.c | 32 ++++++++++++-------------------- - drivers/irqchip/irq-bcm2836.c | 5 +++++ - 2 files changed, 17 insertions(+), 20 deletions(-) - -diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c -index 2fccc5cfe9f3..88abd2e67866 100644 ---- a/drivers/irqchip/irq-bcm2835.c -+++ b/drivers/irqchip/irq-bcm2835.c -@@ -41,8 +41,6 @@ - #include <linux/of_irq.h> - #include <linux/irqchip.h> - #include <linux/irqdomain.h> --#include <linux/mfd/syscon.h> --#include <linux/regmap.h> - - #include <asm/exception.h> - #include <asm/mach/irq.h> -@@ -91,7 +89,7 @@ struct armctrl_ic { - void __iomem *enable[NR_BANKS]; - void __iomem *disable[NR_BANKS]; - struct irq_domain *domain; -- struct regmap *local_regmap; -+ void __iomem *local_base; - }; - - static struct armctrl_ic intc __read_mostly; -@@ -128,24 +126,20 @@ static void armctrl_unmask_irq(struct irq_data *d) - if (d->hwirq >= NUMBER_IRQS) { - if (num_online_cpus() > 1) { - unsigned int data; -- int ret; - -- if (!intc.local_regmap) { -- pr_err("FIQ is disabled due to missing regmap\n"); -+ if (!intc.local_base) { -+ pr_err("FIQ is disabled due to missing arm_local_intc\n"); - return; - } - -- ret = regmap_read(intc.local_regmap, -- ARM_LOCAL_GPU_INT_ROUTING, &data); -- if (ret) { -- pr_err("Failed to read int routing %d\n", ret); -- return; -- } -+ data = readl_relaxed(intc.local_base + -+ ARM_LOCAL_GPU_INT_ROUTING); - - data &= ~0xc; - data |= (1 << 2); -- regmap_write(intc.local_regmap, -- ARM_LOCAL_GPU_INT_ROUTING, data); -+ writel_relaxed(data, -+ intc.local_base + -+ ARM_LOCAL_GPU_INT_ROUTING); - } - - writel_relaxed(REG_FIQ_ENABLE | hwirq_to_fiq(d->hwirq), -@@ -231,12 +225,10 @@ static int __init armctrl_of_init(struct device_node *node, - } - - if (is_2836) { -- intc.local_regmap = -- syscon_regmap_lookup_by_compatible("brcm,bcm2836-arm-local"); -- if (IS_ERR(intc.local_regmap)) { -- pr_err("Failed to get local register map. FIQ is disabled for cpus > 1\n"); -- intc.local_regmap = NULL; -- } -+ extern void __iomem * __attribute__((weak)) arm_local_intc; -+ intc.local_base = arm_local_intc; -+ if (!intc.local_base) -+ pr_err("Failed to get local intc base. FIQ is disabled for cpus > 1\n"); - } - - /* Make a duplicate irq range which is used to enable FIQ */ -diff --git a/drivers/irqchip/irq-bcm2836.c b/drivers/irqchip/irq-bcm2836.c -index c006a8ac10d5..49642bcd0b75 100644 ---- a/drivers/irqchip/irq-bcm2836.c -+++ b/drivers/irqchip/irq-bcm2836.c -@@ -21,6 +21,9 @@ struct bcm2836_arm_irqchip_intc { - - static struct bcm2836_arm_irqchip_intc intc __read_mostly; - -+void __iomem *arm_local_intc; -+EXPORT_SYMBOL_GPL(arm_local_intc); -+ - static void bcm2836_arm_irqchip_mask_per_cpu_irq(unsigned int reg_offset, - unsigned int bit, - int cpu) -@@ -225,6 +228,8 @@ static int __init bcm2836_arm_irqchip_l1_intc_of_init(struct device_node *node, - panic("%pOF: unable to map local interrupt registers\n", node); - } - -+ arm_local_intc = intc.base; -+ - bcm2835_init_local_timer_frequency(); - - intc.domain = irq_domain_add_linear(node, LAST_IRQ + 1, diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0030-lan78xx-Enable-LEDs-and-auto-negotiation.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0030-lan78xx-Enable-LEDs-and-auto-negotiation.patch deleted file mode 100644 index 32d936f4..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0030-lan78xx-Enable-LEDs-and-auto-negotiation.patch +++ /dev/null @@ -1,50 +0,0 @@ -From 8025c128a5a3db5b36c5f72d08cf0b7ac064d70e Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Tue, 17 Oct 2017 15:04:29 +0100 -Subject: [PATCH 030/325] lan78xx: Enable LEDs and auto-negotiation - -For applications of the LAN78xx that don't have valid programmed -EEPROMs or OTPs, enabling both LEDs and auto-negotiation by default -seems reasonable. - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - drivers/net/usb/lan78xx.c | 11 +++++++++++ - 1 file changed, 11 insertions(+) - -diff --git a/drivers/net/usb/lan78xx.c b/drivers/net/usb/lan78xx.c -index e96bc0c6140f..b750ffdd8718 100644 ---- a/drivers/net/usb/lan78xx.c -+++ b/drivers/net/usb/lan78xx.c -@@ -2462,6 +2462,11 @@ static int lan78xx_reset(struct lan78xx_net *dev) - int ret = 0; - unsigned long timeout; - u8 sig; -+ bool has_eeprom; -+ bool has_otp; -+ -+ has_eeprom = !lan78xx_read_eeprom(dev, 0, 0, NULL); -+ has_otp = !lan78xx_read_otp(dev, 0, 0, NULL); - - ret = lan78xx_read_reg(dev, HW_CFG, &buf); - buf |= HW_CFG_LRST_; -@@ -2515,6 +2520,9 @@ static int lan78xx_reset(struct lan78xx_net *dev) - - ret = lan78xx_read_reg(dev, HW_CFG, &buf); - buf |= HW_CFG_MEF_; -+ /* If no valid EEPROM and no valid OTP, enable the LEDs by default */ -+ if (!has_eeprom && !has_otp) -+ buf |= HW_CFG_LED0_EN_ | HW_CFG_LED1_EN_; - ret = lan78xx_write_reg(dev, HW_CFG, buf); - - ret = lan78xx_read_reg(dev, USB_CFG0, &buf); -@@ -2570,6 +2578,9 @@ static int lan78xx_reset(struct lan78xx_net *dev) - buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_; - } - } -+ /* If no valid EEPROM and no valid OTP, enable AUTO negotiation */ -+ if (!has_eeprom && !has_otp) -+ buf |= MAC_CR_AUTO_DUPLEX_ | MAC_CR_AUTO_SPEED_; - ret = lan78xx_write_reg(dev, MAC_CR, buf); - - ret = lan78xx_read_reg(dev, MAC_TX, &buf); diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0031-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0031-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch deleted file mode 100644 index 114d4c18..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0031-amba_pl011-Don-t-use-DT-aliases-for-numbering.patch +++ /dev/null @@ -1,31 +0,0 @@ -From c884a6739790d3bfa8c713e5040b1198e80f6b2b Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Tue, 23 Feb 2016 17:26:48 +0000 -Subject: [PATCH 031/325] amba_pl011: Don't use DT aliases for numbering - -The pl011 driver looks for DT aliases of the form "serial<n>", -and if found uses <n> as the device ID. This can cause -/dev/ttyAMA0 to become /dev/ttyAMA1, which is confusing if the -other serial port is provided by the 8250 driver which doesn't -use the same logic. ---- - drivers/tty/serial/amba-pl011.c | 5 +++++ - 1 file changed, 5 insertions(+) - -diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index 89ade213a1a9..18225dda654b 100644 ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -2578,7 +2578,12 @@ static int pl011_setup_port(struct device *dev, struct uart_amba_port *uap, - if (IS_ERR(base)) - return PTR_ERR(base); - -+ /* Don't use DT serial<n> aliases - it causes the device to -+ be renumbered to ttyAMA1 if it is the second serial port in the -+ system, even though the other one is ttyS0. The 8250 driver -+ doesn't use this logic, so always remains ttyS0. - index = pl011_probe_dt_alias(index, dev); -+ */ - - uap->old_cr = 0; - uap->port.dev = dev; diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0032-amba_pl011-Round-input-clock-up.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0032-amba_pl011-Round-input-clock-up.patch deleted file mode 100644 index 86f0f3ed..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0032-amba_pl011-Round-input-clock-up.patch +++ /dev/null @@ -1,88 +0,0 @@ -From 0146543d380e24737c7bee512defe33ea7bca503 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Wed, 1 Mar 2017 16:07:39 +0000 -Subject: [PATCH 032/325] amba_pl011: Round input clock up - -The UART clock is initialised to be as close to the requested -frequency as possible without exceeding it. Now that there is a -clock manager that returns the actual frequencies, an expected -48MHz clock is reported as 47999625. If the requested baudrate -== requested clock/16, there is no headroom and the slight -reduction in actual clock rate results in failure. - -Detect cases where it looks like a "round" clock was chosen and -adjust the reported clock to match that "round" value. As the -code comment says: - -/* - * If increasing a clock by less than 0.1% changes it - * from ..999.. to ..000.., round up. - */ - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - drivers/tty/serial/amba-pl011.c | 23 +++++++++++++++++++++-- - 1 file changed, 21 insertions(+), 2 deletions(-) - -diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index 18225dda654b..02275f96dbca 100644 ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -1652,6 +1652,23 @@ static void pl011_put_poll_char(struct uart_port *port, - - #endif /* CONFIG_CONSOLE_POLL */ - -+unsigned long pl011_clk_round(unsigned long clk) -+{ -+ unsigned long scaler; -+ -+ /* -+ * If increasing a clock by less than 0.1% changes it -+ * from ..999.. to ..000.., round up. -+ */ -+ scaler = 1; -+ while (scaler * 100000 < clk) -+ scaler *= 10; -+ if ((clk + scaler - 1)/scaler % 1000 == 0) -+ clk = (clk/scaler + 1) * scaler; -+ -+ return clk; -+} -+ - static int pl011_hwinit(struct uart_port *port) - { - struct uart_amba_port *uap = -@@ -1668,7 +1685,7 @@ static int pl011_hwinit(struct uart_port *port) - if (retval) - return retval; - -- uap->port.uartclk = clk_get_rate(uap->clk); -+ uap->port.uartclk = pl011_clk_round(clk_get_rate(uap->clk)); - - /* Clear pending error and receive interrupts */ - pl011_write(UART011_OEIS | UART011_BEIS | UART011_PEIS | -@@ -2324,7 +2341,7 @@ static int __init pl011_console_setup(struct console *co, char *options) - plat->init(); - } - -- uap->port.uartclk = clk_get_rate(uap->clk); -+ uap->port.uartclk = pl011_clk_round(clk_get_rate(uap->clk)); - - if (uap->vendor->fixed_options) { - baud = uap->fixed_baud; -@@ -2509,6 +2526,7 @@ static struct uart_driver amba_reg = { - .cons = AMBA_CONSOLE, - }; - -+#if 0 - static int pl011_probe_dt_alias(int index, struct device *dev) - { - struct device_node *np; -@@ -2540,6 +2558,7 @@ static int pl011_probe_dt_alias(int index, struct device *dev) - - return ret; - } -+#endif - - /* unregisters the driver also if no more ports are left */ - static void pl011_unregister_port(struct uart_amba_port *uap) diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0033-amba_pl011-Insert-mb-for-correct-FIFO-handling.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0033-amba_pl011-Insert-mb-for-correct-FIFO-handling.patch deleted file mode 100644 index 905d161e..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0033-amba_pl011-Insert-mb-for-correct-FIFO-handling.patch +++ /dev/null @@ -1,29 +0,0 @@ -From 18e6daaa4bb92e72064511170abf8ca67b594771 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Fri, 29 Sep 2017 10:32:19 +0100 -Subject: [PATCH 033/325] amba_pl011: Insert mb() for correct FIFO handling - -The pl011 register accessor functions use the _relaxed versions of the -standard readl() and writel() functions, meaning that there are no -automatic memory barriers. When polling a FIFO status register to check -for fullness, it is necessary to ensure that any outstanding writes have -completed; otherwise the flags are effectively stale, making it possible -that the next write is to a full FIFO. - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - drivers/tty/serial/amba-pl011.c | 1 + - 1 file changed, 1 insertion(+) - -diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index 02275f96dbca..39d717e94af3 100644 ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -1385,6 +1385,7 @@ static bool pl011_tx_char(struct uart_amba_port *uap, unsigned char c, - return false; /* unable to transmit character */ - - pl011_write(c, uap, REG_DR); -+ mb(); - uap->port.icount.tx++; - - return true; diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0034-amba_pl011-Add-cts-event-workaround-DT-property.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0034-amba_pl011-Add-cts-event-workaround-DT-property.patch deleted file mode 100644 index 86b95f0c..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0034-amba_pl011-Add-cts-event-workaround-DT-property.patch +++ /dev/null @@ -1,51 +0,0 @@ -From 36abcdf1d1457d645f5accc9824efcda74d2eeb8 Mon Sep 17 00:00:00 2001 -From: Phil Elwell <phil@raspberrypi.org> -Date: Fri, 29 Sep 2017 10:32:19 +0100 -Subject: [PATCH 034/325] amba_pl011: Add cts-event-workaround DT property - -The BCM2835 PL011 implementation seems to have a bug that can lead to a -transmission lockup if CTS changes frequently. A workaround was added to -the driver with a vendor-specific flag to enable it, but this flag is -currently not set for ARM implementations. - -Add a "cts-event-workaround" property to Pi DTBs and use the presence -of that property to force the flag to be enabled in the driver. - -See: https://github.com/raspberrypi/linux/issues/1280 - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> ---- - Documentation/devicetree/bindings/serial/pl011.txt | 3 +++ - drivers/tty/serial/amba-pl011.c | 5 +++++ - 2 files changed, 8 insertions(+) - -diff --git a/Documentation/devicetree/bindings/serial/pl011.txt b/Documentation/devicetree/bindings/serial/pl011.txt -index 77863aefe9ef..8d65b0ec2828 100644 ---- a/Documentation/devicetree/bindings/serial/pl011.txt -+++ b/Documentation/devicetree/bindings/serial/pl011.txt -@@ -35,6 +35,9 @@ Optional properties: - - poll-timeout-ms: - Poll timeout when auto-poll is set, default - 3000ms. -+- cts-event-workaround: -+ Enables the (otherwise vendor-specific) workaround for the -+ CTS-induced TX lockup. - - See also bindings/arm/primecell.txt - -diff --git a/drivers/tty/serial/amba-pl011.c b/drivers/tty/serial/amba-pl011.c -index 39d717e94af3..6f15f32fa194 100644 ---- a/drivers/tty/serial/amba-pl011.c -+++ b/drivers/tty/serial/amba-pl011.c -@@ -2661,6 +2661,11 @@ static int pl011_probe(struct amba_device *dev, const struct amba_id *id) - if (IS_ERR(uap->clk)) - return PTR_ERR(uap->clk); - -+ if (of_property_read_bool(dev->dev.of_node, "cts-event-workaround")) { -+ vendor->cts_event_workaround = true; -+ dev_info(&dev->dev, "cts_event_workaround enabled\n"); -+ } -+ - uap->reg_offset = vendor->reg_offset; - uap->vendor = vendor; - uap->fifosize = vendor->get_fifosize(dev); diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0035-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0035-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch deleted file mode 100644 index 1a2fc8b2..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0035-pinctrl-bcm2835-Set-base-to-0-give-expected-gpio-num.patch +++ /dev/null @@ -1,24 +0,0 @@ -From 2fc88882c1a584012f3669fedd4a8c0899704ad2 Mon Sep 17 00:00:00 2001 -From: notro <notro@tronnes.org> -Date: Thu, 10 Jul 2014 13:59:47 +0200 -Subject: [PATCH 035/325] pinctrl-bcm2835: Set base to 0 give expected gpio - numbering - -Signed-off-by: Noralf Tronnes <notro@tronnes.org> ---- - drivers/pinctrl/bcm/pinctrl-bcm2835.c | 2 +- - 1 file changed, 1 insertion(+), 1 deletion(-) - -diff --git a/drivers/pinctrl/bcm/pinctrl-bcm2835.c b/drivers/pinctrl/bcm/pinctrl-bcm2835.c -index f180aa44a422..f97089c0c69d 100644 ---- a/drivers/pinctrl/bcm/pinctrl-bcm2835.c -+++ b/drivers/pinctrl/bcm/pinctrl-bcm2835.c -@@ -341,7 +341,7 @@ static const struct gpio_chip bcm2835_gpio_chip = { - .get_direction = bcm2835_gpio_get_direction, - .get = bcm2835_gpio_get, - .set = bcm2835_gpio_set, -- .base = -1, -+ .base = 0, - .ngpio = BCM2835_NUM_GPIOS, - .can_sleep = false, - }; diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0036-Main-bcm2708-bcm2709-linux-port.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0036-Main-bcm2708-bcm2709-linux-port.patch deleted file mode 100644 index 663aa50e..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0036-Main-bcm2708-bcm2709-linux-port.patch +++ /dev/null @@ -1,158 +0,0 @@ -From 120af58d3e4995b77d8d2ebc8837472b65934b2d Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Sun, 12 May 2013 12:24:19 +0100 -Subject: [PATCH 036/325] Main bcm2708/bcm2709 linux port -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: popcornmix <popcornmix@gmail.com> -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> - -bcm2709: Drop platform smp and timer init code - -irq-bcm2836 handles this through these functions: -bcm2835_init_local_timer_frequency() -bcm2836_arm_irqchip_smp_init() - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> - -bcm270x: Use watchdog for reboot/poweroff - -The watchdog driver already has support for reboot/poweroff. -Make use of this and remove the code from the platform files. - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> - -board_bcm2835: Remove coherent dma pool increase - API has gone ---- - arch/arm/mach-bcm/Kconfig | 1 + - arch/arm/mm/proc-v6.S | 15 ++++++++++++--- - drivers/irqchip/irq-bcm2835.c | 7 ++++++- - drivers/mailbox/bcm2835-mailbox.c | 18 ++++++++++++++++-- - 4 files changed, 35 insertions(+), 6 deletions(-) - -diff --git a/arch/arm/mach-bcm/Kconfig b/arch/arm/mach-bcm/Kconfig -index 9ca6f33d4440..abab75a17916 100644 ---- a/arch/arm/mach-bcm/Kconfig -+++ b/arch/arm/mach-bcm/Kconfig -@@ -168,6 +168,7 @@ config ARCH_BCM2835 - select FIQ - select PINCTRL - select PINCTRL_BCM2835 -+ select MFD_SYSCON if ARCH_MULTI_V7 - help - This enables support for the Broadcom BCM2835 and BCM2836 SoCs. - This SoC is used in the Raspberry Pi and Roku 2 devices. -diff --git a/arch/arm/mm/proc-v6.S b/arch/arm/mm/proc-v6.S -index 06d890a2342b..30d96e81c0e0 100644 ---- a/arch/arm/mm/proc-v6.S -+++ b/arch/arm/mm/proc-v6.S -@@ -73,10 +73,19 @@ ENDPROC(cpu_v6_reset) - * - * IRQs are already disabled. - */ -+ -+/* See jira SW-5991 for details of this workaround */ - ENTRY(cpu_v6_do_idle) -- mov r1, #0 -- mcr p15, 0, r1, c7, c10, 4 @ DWB - WFI may enter a low-power mode -- mcr p15, 0, r1, c7, c0, 4 @ wait for interrupt -+ .align 5 -+ mov r1, #2 -+1: subs r1, #1 -+ nop -+ mcreq p15, 0, r1, c7, c10, 4 @ DWB - WFI may enter a low-power mode -+ mcreq p15, 0, r1, c7, c0, 4 @ wait for interrupt -+ nop -+ nop -+ nop -+ bne 1b - ret lr - - ENTRY(cpu_v6_dcache_clean_area) -diff --git a/drivers/irqchip/irq-bcm2835.c b/drivers/irqchip/irq-bcm2835.c -index 88abd2e67866..ff7b998579c1 100644 ---- a/drivers/irqchip/irq-bcm2835.c -+++ b/drivers/irqchip/irq-bcm2835.c -@@ -43,7 +43,9 @@ - #include <linux/irqdomain.h> - - #include <asm/exception.h> -+#ifndef CONFIG_ARM64 - #include <asm/mach/irq.h> -+#endif - - /* Put the bank and irq (32 bits) into the hwirq */ - #define MAKE_HWIRQ(b, n) (((b) << 5) | (n)) -@@ -71,6 +73,7 @@ - #define NR_BANKS 3 - #define IRQS_PER_BANK 32 - #define NUMBER_IRQS MAKE_HWIRQ(NR_BANKS, 0) -+#undef FIQ_START - #define FIQ_START (NR_IRQS_BANK0 + MAKE_HWIRQ(NR_BANKS - 1, 0)) - - static const int reg_pending[] __initconst = { 0x00, 0x04, 0x08 }; -@@ -238,10 +241,12 @@ static int __init armctrl_of_init(struct device_node *node, - MAKE_HWIRQ(b, i) + NUMBER_IRQS); - BUG_ON(irq <= 0); - irq_set_chip(irq, &armctrl_chip); -- set_irq_flags(irq, IRQF_VALID | IRQF_PROBE); -+ irq_set_probe(irq); - } - } -+#ifndef CONFIG_ARM64 - init_FIQ(FIQ_START); -+#endif - - return 0; - } -diff --git a/drivers/mailbox/bcm2835-mailbox.c b/drivers/mailbox/bcm2835-mailbox.c -index 39761d190545..9766d8b50778 100644 ---- a/drivers/mailbox/bcm2835-mailbox.c -+++ b/drivers/mailbox/bcm2835-mailbox.c -@@ -45,12 +45,15 @@ - #define MAIL1_WRT (ARM_0_MAIL1 + 0x00) - #define MAIL1_STA (ARM_0_MAIL1 + 0x18) - -+/* On ARCH_BCM270x these come through <linux/interrupt.h> (arm_control.h ) */ -+#ifndef ARM_MS_FULL - /* Status register: FIFO state. */ - #define ARM_MS_FULL BIT(31) - #define ARM_MS_EMPTY BIT(30) - - /* Configuration register: Enable interrupts. */ - #define ARM_MC_IHAVEDATAIRQEN BIT(0) -+#endif - - struct bcm2835_mbox { - void __iomem *regs; -@@ -145,7 +148,7 @@ static int bcm2835_mbox_probe(struct platform_device *pdev) - return -ENOMEM; - spin_lock_init(&mbox->lock); - -- ret = devm_request_irq(dev, irq_of_parse_and_map(dev->of_node, 0), -+ ret = devm_request_irq(dev, platform_get_irq(pdev, 0), - bcm2835_mbox_irq, 0, dev_name(dev), mbox); - if (ret) { - dev_err(dev, "Failed to register a mailbox IRQ handler: %d\n", -@@ -195,7 +198,18 @@ static struct platform_driver bcm2835_mbox_driver = { - }, - .probe = bcm2835_mbox_probe, - }; --module_platform_driver(bcm2835_mbox_driver); -+ -+static int __init bcm2835_mbox_init(void) -+{ -+ return platform_driver_register(&bcm2835_mbox_driver); -+} -+arch_initcall(bcm2835_mbox_init); -+ -+static void __init bcm2835_mbox_exit(void) -+{ -+ platform_driver_unregister(&bcm2835_mbox_driver); -+} -+module_exit(bcm2835_mbox_exit); - - MODULE_AUTHOR("Lubomir Rintel <lkundrak@v3.sk>"); - MODULE_DESCRIPTION("BCM2835 mailbox IPC driver"); diff --git a/sys-kernel/boest-v5.0.21/raspberrypi/0037-Add-dwc_otg-driver.patch b/sys-kernel/boest-v5.0.21/raspberrypi/0037-Add-dwc_otg-driver.patch deleted file mode 100644 index e8d0a841..00000000 --- a/sys-kernel/boest-v5.0.21/raspberrypi/0037-Add-dwc_otg-driver.patch +++ /dev/null @@ -1,61396 +0,0 @@ -From f7c0679f3fa41109ff3b3fe7a6610df172fa37a6 Mon Sep 17 00:00:00 2001 -From: popcornmix <popcornmix@gmail.com> -Date: Wed, 1 May 2013 19:46:17 +0100 -Subject: [PATCH 037/325] Add dwc_otg driver -MIME-Version: 1.0 -Content-Type: text/plain; charset=UTF-8 -Content-Transfer-Encoding: 8bit - -Signed-off-by: popcornmix <popcornmix@gmail.com> - -usb: dwc: fix lockdep false positive - -Signed-off-by: Kari Suvanto <karis79@gmail.com> - -usb: dwc: fix inconsistent lock state - -Signed-off-by: Kari Suvanto <karis79@gmail.com> - -Add FIQ patch to dwc_otg driver. Enable with dwc_otg.fiq_fix_enable=1. Should give about 10% more ARM performance. -Thanks to Gordon and Costas - -Avoid dynamic memory allocation for channel lock in USB driver. Thanks ddv2005. - -Add NAK holdoff scheme. Enabled by default, disable with dwc_otg.nak_holdoff_enable=0. Thanks gsh - -Make sure we wait for the reset to finish - -dwc_otg: fix bug in dwc_otg_hcd.c resulting in silent kernel - memory corruption, escalating to OOPS under high USB load. - -dwc_otg: Fix unsafe access of QTD during URB enqueue - -In dwc_otg_hcd_urb_enqueue during qtd creation, it was possible that the -transaction could complete almost immediately after the qtd was assigned -to a host channel during URB enqueue, which meant the qtd pointer was no -longer valid having been completed and removed. Usually, this resulted in -an OOPS during URB submission. By predetermining whether transactions -need to be queued or not, this unsafe pointer access is avoided. - -This bug was only evident on the Pi model A where a device was attached -that had no periodic endpoints (e.g. USB pendrive or some wlan devices). - -dwc_otg: Fix incorrect URB allocation error handling - -If the memory allocation for a dwc_otg_urb failed, the kernel would OOPS -because for some reason a member of the *unallocated* struct was set to -zero. Error handling changed to fail correctly. - -dwc_otg: fix potential use-after-free case in interrupt handler - -If a transaction had previously aborted, certain interrupts are -enabled to track error counts and reset where necessary. On IN -endpoints the host generates an ACK interrupt near-simultaneously -with completion of transfer. In the case where this transfer had -previously had an error, this results in a use-after-free on -the QTD memory space with a 1-byte length being overwritten to -0x00. - -dwc_otg: add handling of SPLIT transaction data toggle errors - -Previously a data toggle error on packets from a USB1.1 device behind -a TT would result in the Pi locking up as the driver never handled -the associated interrupt. Patch adds basic retry mechanism and -interrupt acknowledgement to cater for either a chance toggle error or -for devices that have a broken initial toggle state (FT8U232/FT232BM). - -dwc_otg: implement tasklet for returning URBs to usbcore hcd layer - -The dwc_otg driver interrupt handler for transfer completion will spend -a very long time with interrupts disabled when a URB is completed - -this is because usb_hcd_giveback_urb is called from within the handler -which for a USB device driver with complicated processing (e.g. webcam) -will take an exorbitant amount of time to complete. This results in -missed completion interrupts for other USB packets which lead to them -being dropped due to microframe overruns. - -This patch splits returning the URB to the usb hcd layer into a -high-priority tasklet. This will have most benefit for isochronous IN -transfers but will also have incidental benefit where multiple periodic -devices are active at once. - -dwc_otg: fix NAK holdoff and allow on split transactions only - -This corrects a bug where if a single active non-periodic endpoint -had at least one transaction in its qh, on frnum == MAX_FRNUM the qh -would get skipped and never get queued again. This would result in -a silent device until error detection (automatic or otherwise) would -either reset the device or flush and requeue the URBs. - -Additionally the NAK holdoff was enabled for all transactions - this -would potentially stall a HS endpoint for 1ms if a previous error state -enabled this interrupt and the next response was a NAK. Fix so that -only split transactions get held off. - -dwc_otg: Call usb_hcd_unlink_urb_from_ep with lock held in completion handler - -usb_hcd_unlink_urb_from_ep must be called with the HCD lock held. Calling it -asynchronously in the tasklet was not safe (regression in -c4564d4a1a0a9b10d4419e48239f5d99e88d2667). - -This change unlinks it from the endpoint prior to queueing it for handling in -the tasklet, and also adds a check to ensure the urb is OK to be unlinked -before doing so. - -NULL pointer dereference kernel oopses had been observed in usb_hcd_giveback_urb -when a USB device was unplugged/replugged during data transfer. This effect -was reproduced using automated USB port power control, hundreds of replug -events were performed during active transfers to confirm that the problem was -eliminated. - -USB fix using a FIQ to implement split transactions - -This commit adds a FIQ implementaion that schedules -the split transactions using a FIQ so we don't get -held off by the interrupt latency of Linux - -dwc_otg: fix device attributes and avoid kernel warnings on boot - -dcw_otg: avoid logging function that can cause panics - -See: https://github.com/raspberrypi/firmware/issues/21 -Thanks to cleverca22 for fix - -dwc_otg: mask correct interrupts after transaction error recovery - -The dwc_otg driver will unmask certain interrupts on a transaction -that previously halted in the error state in order to reset the -QTD error count. The various fine-grained interrupt handlers do not -consider that other interrupts besides themselves were unmasked. - -By disabling the two other interrupts only ever enabled in DMA mode -for this purpose, we can avoid unnecessary function calls in the -IRQ handler. This will also prevent an unneccesary FIQ interrupt -from being generated if the FIQ is enabled. - -dwc_otg: fiq: prevent FIQ thrash and incorrect state passing to IRQ - -In the case of a transaction to a device that had previously aborted -due to an error, several interrupts are enabled to reset the error -count when a device responds. This has the side-effect of making the -FIQ thrash because the hardware will generate multiple instances of -a NAK on an IN bulk/interrupt endpoint and multiple instances of ACK -on an OUT bulk/interrupt endpoint. Make the FIQ mask and clear the -associated interrupts. - -Additionally, on non-split transactions make sure that only unmasked -interrupts are cleared. This caused a hard-to-trigger but serious -race condition when you had the combination of an endpoint awaiting -error recovery and a transaction completed on an endpoint - due to -the sequencing and timing of interrupts generated by the dwc_otg core, -it was possible to confuse the IRQ handler. - -Fix function tracing - -dwc_otg: whitespace cleanup in dwc_otg_urb_enqueue - -dwc_otg: prevent OOPSes during device disconnects - -The dwc_otg_urb_enqueue function is thread-unsafe. In particular the -access of urb->hcpriv, usb_hcd_link_urb_to_ep, dwc_otg_urb->qtd and -friends does not occur within a critical section and so if a device -was unplugged during activity there was a high chance that the -usbcore hub_thread would try to disable the endpoint with partially- -formed entries in the URB queue. This would result in BUG() or null -pointer dereferences. - -Fix so that access of urb->hcpriv, enqueuing to the hardware and -adding to usbcore endpoint URB lists is contained within a single -critical section. - -dwc_otg: prevent BUG() in TT allocation if hub address is > 16 - -A fixed-size array is used to track TT allocation. This was -previously set to 16 which caused a crash because -dwc_otg_hcd_allocate_port would read past the end of the array. - -This was hit if a hub was plugged in which enumerated as addr > 16, -due to previous device resets or unplugs. - -Also add #ifdef FIQ_DEBUG around hcd->hub_port_alloc[], which grows -to a large size if 128 hub addresses are supported. This field is -for debug only for tracking which frame an allocate happened in. - -dwc_otg: make channel halts with unknown state less damaging - -If the IRQ received a channel halt interrupt through the FIQ -with no other bits set, the IRQ would not release the host -channel and never complete the URB. - -Add catchall handling to treat as a transaction error and retry. - -dwc_otg: fiq_split: use TTs with more granularity - -This fixes certain issues with split transaction scheduling. - -- Isochronous multi-packet OUT transactions now hog the TT until - they are completed - this prevents hubs aborting transactions - if they get a periodic start-split out-of-order -- Don't perform TT allocation on non-periodic endpoints - this - allows simultaneous use of the TT's bulk/control and periodic - transaction buffers - -This commit will mainly affect USB audio playback. - -dwc_otg: fix potential sleep while atomic during urb enqueue - -Fixes a regression introduced with eb1b482a. Kmalloc called from -dwc_otg_hcd_qtd_add / dwc_otg_hcd_qtd_create did not always have -the GPF_ATOMIC flag set. Force this flag when inside the larger -critical section. - -dwc_otg: make fiq_split_enable imply fiq_fix_enable - -Failing to set up the FIQ correctly would result in -"IRQ 32: nobody cared" errors in dmesg. - -dwc_otg: prevent crashes on host port disconnects - -Fix several issues resulting in crashes or inconsistent state -if a Model A root port was disconnected. - -- Clean up queue heads properly in kill_urbs_in_qh_list by - removing the empty QHs from the schedule lists -- Set the halt status properly to prevent IRQ handlers from - using freed memory -- Add fiq_split related cleanup for saved registers -- Make microframe scheduling reclaim host channels if - active during a disconnect -- Abort URBs with -ESHUTDOWN status response, informing - device drivers so they respond in a more correct fashion - and don't try to resubmit URBs -- Prevent IRQ handlers from attempting to handle channel - interrupts if the associated URB was dequeued (and the - driver state was cleared) - -dwc_otg: prevent leaking URBs during enqueue - -A dwc_otg_urb would get leaked if the HCD enqueue function -failed for any reason. Free the URB at the appropriate points. - -dwc_otg: Enable NAK holdoff for control split transactions - -Certain low-speed devices take a very long time to complete a -data or status stage of a control transaction, producing NAK -responses until they complete internal processing - the USB2.0 -spec limit is up to 500mS. This causes the same type of interrupt -storm as seen with USB-serial dongles prior to c8edb238. - -In certain circumstances, usually while booting, this interrupt -storm could cause SD card timeouts. - -dwc_otg: Fix for occasional lockup on boot when doing a USB reset - -dwc_otg: Don't issue traffic to LS devices in FS mode - -Issuing low-speed packets when the root port is in full-speed mode -causes the root port to stop responding. Explicitly fail when -enqueuing URBs to a LS endpoint on a FS bus. - -Fix ARM architecture issue with local_irq_restore() - -If local_fiq_enable() is called before a local_irq_restore(flags) where -the flags variable has the F bit set, the FIQ will be erroneously disabled. - -Fixup arch_local_irq_restore to avoid trampling the F bit in CPSR. - -Also fix some of the hacks previously implemented for previous dwc_otg -incarnations. - -dwc_otg: fiq_fsm: Base commit for driver rewrite - -This commit removes the previous FIQ fixes entirely and adds fiq_fsm. - -This rewrite features much more complete support for split transactions -and takes into account several OTG hardware bugs. High-speed -isochronous transactions are also capable of being performed by fiq_fsm. - -All driver options have been removed and replaced with: - - dwc_otg.fiq_enable (bool) - - dwc_otg.fiq_fsm_enable (bool) - - dwc_otg.fiq_fsm_mask (bitmask) - - dwc_otg.nak_holdoff (unsigned int) - -Defaults are specified such that fiq_fsm behaves similarly to the -previously implemented FIQ fixes. - -fiq_fsm: Push error recovery into the FIQ when fiq_fsm is used - -If the transfer associated with a QTD failed due to a bus error, the HCD -would retry the transfer up to 3 times (implementing the USB2.0 -three-strikes retry in software). - -Due to the masking mechanism used by fiq_fsm, it is only possible to pass -a single interrupt through to the HCD per-transfer. - -In this instance host channels would fall off the radar because the error -reset would function, but the subsequent channel halt would be lost. - -Push the error count reset into the FIQ handler. - -fiq_fsm: Implement timeout mechanism - -For full-speed endpoints with a large packet size, interrupt latency -runs the risk of the FIQ starting a transaction too late in a full-speed -frame. If the device is still transmitting data when EOF2 for the -downstream frame occurs, the hub will disable the port. This change is -not reflected in the hub status endpoint and the device becomes -unresponsive. - -Prevent high-bandwidth transactions from being started too late in a -frame. The mechanism is not guaranteed: a combination of bit stuffing -and hub latency may still result in a device overrunning. - -fiq_fsm: fix bounce buffer utilisation for Isochronous OUT - -Multi-packet isochronous OUT transactions were subject to a few bounday -bugs. Fix them. - -Audio playback is now much more robust: however, an issue stands with -devices that have adaptive sinks - ALSA plays samples too fast. - -dwc_otg: Return full-speed frame numbers in HS mode - -The frame counter increments on every *microframe* in high-speed mode. -Most device drivers expect this number to be in full-speed frames - this -caused considerable confusion to e.g. snd_usb_audio which uses the -frame counter to estimate the number of samples played. - -fiq_fsm: save PID on completion of interrupt OUT transfers - -Also add edge case handling for interrupt transports. - -Note that for periodic split IN, data toggles are unimplemented in the -OTG host hardware - it unconditionally accepts any PID. - -fiq_fsm: add missing case for fiq_fsm_tt_in_use() - -Certain combinations of bitrate and endpoint activity could -result in a periodic transaction erroneously getting started -while the previous Isochronous OUT was still active. - -fiq_fsm: clear hcintmsk for aborted transactions - -Prevents the FIQ from erroneously handling interrupts -on a timed out channel. - -fiq_fsm: enable by default - -fiq_fsm: fix dequeues for non-periodic split transactions - -If a dequeue happened between the SSPLIT and CSPLIT phases of the -transaction, the HCD would never receive an interrupt. - -fiq_fsm: Disable by default - -fiq_fsm: Handle HC babble errors - -The HCTSIZ transfer size field raises a babble interrupt if -the counter wraps. Handle the resulting interrupt in this case. - -dwc_otg: fix interrupt registration for fiq_enable=0 - -Additionally make the module parameter conditional for wherever -hcd->fiq_state is touched. - -fiq_fsm: Enable by default - -dwc_otg: Fix various issues with root port and transaction errors - -Process the host port interrupts correctly (and don't trample them). -Root port hotplug now functional again. - -Fix a few thinkos with the transaction error passthrough for fiq_fsm. - -fiq_fsm: Implement hack for Split Interrupt transactions - -Hubs aren't too picky about which endpoint we send Control type split -transactions to. By treating Interrupt transfers as Control, it is -possible to use the non-periodic queue in the OTG core as well as the -non-periodic FIFOs in the hub itself. This massively reduces the -microframe exclusivity/contention that periodic split transactions -otherwise have to enforce. - -It goes without saying that this is a fairly egregious USB specification -violation, but it works. - -Original idea by Hans Petter Selasky @ FreeBSD.org. - -dwc_otg: FIQ support on SMP. Set up FIQ stack and handler on Core 0 only. - -dwc_otg: introduce fiq_fsm_spin(un|)lock() - -SMP safety for the FIQ relies on register read-modify write cycles being -completed in the correct order. Several places in the DWC code modify -registers also touched by the FIQ. Protect these by a bare-bones lock -mechanism. - -This also makes it possible to run the FIQ and IRQ handlers on different -cores. - -fiq_fsm: fix build on bcm2708 and bcm2709 platforms - -dwc_otg: put some barriers back where they should be for UP - -bcm2709/dwc_otg: Setup FIQ on core 1 if >1 core active - -dwc_otg: fixup read-modify-write in critical paths - -Be more careful about read-modify-write on registers that the FIQ -also touches. - -Guard fiq_fsm_spin_lock with fiq_enable check - -fiq_fsm: Falling out of the state machine isn't fatal - -This edge case can be hit if the port is disabled while the FIQ is -in the middle of a transaction. Make the effects less severe. - -Also get rid of the useless return value. - -squash: dwc_otg: Allow to build without SMP - -usb: core: make overcurrent messages more prominent - -Hub overcurrent messages are more serious than "debug". Increase loglevel. - -usb: dwc_otg: Don't use dma_to_virt() - -Commit 6ce0d20 changes dma_to_virt() which breaks this driver. -Open code the old dma_to_virt() implementation to work around this. - -Limit the use of __bus_to_virt() to cases where transfer_buffer_length -is set and transfer_buffer is not set. This is done to increase the -chance that this driver will also work on ARCH_BCM2835. - -transfer_buffer should not be NULL if the length is set, but the -comment in the code indicates that there are situations where this -might happen. drivers/usb/isp1760/isp1760-hcd.c also has a similar -comment pointing to a possible: 'usb storage / SCSI bug'. - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> - -dwc_otg: Fix crash when fiq_enable=0 - -dwc_otg: fiq_fsm: Make high-speed isochronous strided transfers work properly - -Certain low-bandwidth high-speed USB devices (specialist audio devices, -compressed-frame webcams) have packet intervals > 1 microframe. - -Stride these transfers in the FIQ by using the start-of-frame interrupt -to restart the channel at the right time. - -dwc_otg: Force host mode to fix incorrect compute module boards - -dwc_otg: Add ARCH_BCM2835 support - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> - -dwc_otg: Simplify FIQ irq number code - -Dropping ATAGS means we can simplify the FIQ irq number code. -Also add error checking on the returned irq number. - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> - -dwc_otg: Remove duplicate gadget probe/unregister function - -dwc_otg: Properly set the HFIR - -Douglas Anderson reported: - -According to the most up to date version of the dwc2 databook, the FRINT -field of the HFIR register should be programmed to: -* 125 us * (PHY clock freq for HS) - 1 -* 1000 us * (PHY clock freq for FS/LS) - 1 - -This is opposed to older versions of the doc that claimed it should be: -* 125 us * (PHY clock freq for HS) -* 1000 us * (PHY clock freq for FS/LS) - -and reported lower timing jitter on a USB analyser - -dcw_otg: trim xfer length when buffer larger than allocated size is received - -dwc_otg: Don't free qh align buffers in atomic context - -dwc_otg: Enable the hack for Split Interrupt transactions by default - -dwc_otg.fiq_fsm_mask=0xF has long been a suggestion for users with audio stutters or other USB bandwidth issues. -So far we are aware of many success stories but no failure caused by this setting. -Make it a default to learn more. - -See: https://www.raspberrypi.org/forums/viewtopic.php?f=28&t=70437 - -Signed-off-by: popcornmix <popcornmix@gmail.com> - -dwc_otg: Use kzalloc when suitable - -dwc_otg: Pass struct device to dma_alloc*() - -This makes it possible to get the bus address from Device Tree. - -Signed-off-by: Noralf Trønnes <noralf@tronnes.org> - -dwc_otg: fix summarize urb->actual_length for isochronous transfers - -Kernel does not copy input data of ISO transfers to userspace -if actual_length is set only in ISO transfers and not summarized -in urb->actual_length. Fixes raspberrypi/linux#903 - -fiq_fsm: Use correct states when starting isoc OUT transfers - -In fiq_fsm_start_next_periodic() if an isochronous OUT transfer -was selected, no regard was given as to whether this was a single-packet -transfer or a multi-packet staged transfer. - -For single-packet transfers, this had the effect of repeatedly sending -OUT packets with bogus data and lengths. - -Eventually if the channel was repeatedly enabled enough times, this -would lock up the OTG core and no further bus transfers would happen. - -Set the FSM state up properly if we select a single-packet transfer. - -Fixes https://github.com/raspberrypi/linux/issues/1842 - -dwc_otg: make nak_holdoff work as intended with empty queues - -If URBs reading from non-periodic split endpoints were dequeued and -the last transfer from the endpoint was a NAK handshake, the resulting -qh->nak_frame value was stale which would result in unnecessarily long -polling intervals for the first subsequent transfer with a fresh URB. - -Fixup qh->nak_frame in dwc_otg_hcd_urb_dequeue and also guard against -a case where a single URB is submitted to the endpoint, a NAK was -received on the transfer immediately prior to receiving data and the -device subsequently resubmits another URB past the qh->nak_frame interval. - -Fixes https://github.com/raspberrypi/linux/issues/1709 - -dwc_otg: fix split transaction data toggle handling around dequeues - -See https://github.com/raspberrypi/linux/issues/1709 - -Fix several issues regarding endpoint state when URBs are dequeued -- If the HCD is disconnected, flush FIQ-enabled channels properly -- Save the data toggle state for bulk endpoints if the last transfer - from an endpoint where URBs were dequeued returned a data packet -- Reset hc->start_pkt_count properly in assign_and_init_hc() - -dwc_otg: fix several potential crash sources - -On root port disconnect events, the host driver state is cleared and -in-progress host channels are forcibly stopped. This doesn't play -well with the FIQ running in the background, so: -- Guard the disconnect callback with both the host spinlock and FIQ - spinlock -- Move qtd dereference in dwc_otg_handle_hc_fsm() after the early-out - so we don't dereference a qtd that has gone away -- Turn catch-all BUG()s in dwc_otg_handle_hc_fsm() into warnings. - -dwc_otg: delete hcd->channel_lock - -The lock serves no purpose as it is only held while the HCD spinlock -is already being held. - -dwc_otg: remove unnecessary dma-mode channel halts on disconnect interrupt - -Host channels are already halted in kill_urbs_in_qh_list() with the -subsequent interrupt processing behaving as if the URB was dequeued -via HCD callback. - -There's no need to clobber the host channel registers a second time -as this exposes races between the driver and host channel resulting -in hcd->free_hc_list becoming corrupted. - -dwcotg: Allow to build without FIQ on ARM64 - -Signed-off-by: popcornmix <popcornmix@gmail.com> - -dwc_otg: make periodic scheduling behave properly for FS buses - -If the root port is in full-speed mode, transfer times at 12mbit/s -would be calculated but matched against high-speed quotas. - -Reinitialise hcd->frame_usecs[i] on each port enable event so that -full-speed bandwidth can be tracked sensibly. - -Also, don't bother using the FIQ for transfers when in full-speed -mode - at the slower bus speed, interrupt frequency is reduced by -an order of magnitude. - -Related issue: https://github.com/raspberrypi/linux/issues/2020 - -dwc_otg: fiq_fsm: Make isochronous compatibility checks work properly - -Get rid of the spammy printk and local pointer mangling. -Also, there is a nominal benefit for using fiq_fsm for isochronous -transfers in FS mode (~1.1k IRQs per second vs 2.1k IRQs per second) -so remove the root port speed check. - -dwc_otg: add module parameter int_ep_interval_min - -Add a module parameter (defaulting to ignored) that clamps the polling rate -of high-speed Interrupt endpoints to a minimum microframe interval. - -The parameter is modifiable at runtime as it is used when activating new -endpoints (such as on device connect). - -dwc_otg: fiq_fsm: Add non-periodic TT exclusivity constraints - -Certain hub types do not discriminate between pipe direction (IN or OUT) -when considering non-periodic transfers. Therefore these hubs get confused -if multiple transfers are issued in different directions with the same -device address and endpoint number. - -Constrain queuing non-periodic split transactions so they are performed -serially in such cases. - -Related: https://github.com/raspberrypi/linux/issues/2024 - -dwc_otg: Fixup change to DRIVER_ATTR interface - -dwc_otg: Fix compilation warnings - -Signed-off-by: Phil Elwell <phil@raspberrypi.org> - -USB_DWCOTG: Disable building dwc_otg as a module (#2265) - -When dwc_otg is built as a module, build will fail with the following -error: - -ERROR: "DWC_TASK_HI_SCHEDULE" [drivers/usb/host/dwc_otg/dwc_otg.ko] undefined! -scripts/Makefile.modpost:91: recipe for target '__modpost' failed -make[1]: *** [__modpost] Error 1 -Makefile:1199: recipe for target 'modules' failed -make: *** [modules] Error 2 - -Even if the error is solved by including the missing -DWC_TASK_HI_SCHEDULE function, the kernel will panic when loading -dwc_otg. - -As a workaround, simply prevent user from building dwc_otg as a module -as the current kernel does not support it. - -See: https://github.com/raspberrypi/linux/issues/2258 - -Signed-off-by: Malik Olivier Boussejra <malik@boussejra.com> - -dwc_otg: New timer API - -dwc_otg: Fix removed ACCESS_ONCE->READ_ONCE - -dwc_otg: don't unconditionally force host mode in dwc_otg_cil_init() - -Add the ability to disable force_host_mode for those that want to use -dwc_otg in both device and host modes. - -dwc_otg: Fix a regression when dequeueing isochronous transfers - -In 282bed95 (dwc_otg: make nak_holdoff work as intended with empty queues) -the dequeue mechanism was changed to leave FIQ-enabled transfers to run -to completion - to avoid leaving hub TT buffers with stale packets lying -around. - -This broke FIQ-accelerated isochronous transfers, as this then meant that -dozens of transfers were performed after the dequeue function returned. - -Restore the state machine fence for isochronous transfers. - -fiq_fsm: rewind DMA pointer for OUT transactions that fail (#2288) - -See: https://github.com/raspberrypi/linux/issues/2140 - -dwc_otg: add smp_mb() to prevent driver state corruption on boot - -Occasional crashes have been seen where the FIQ code dereferences -invalid/random pointers immediately after being set up, leading to -panic on boot. - -The crash occurs as the FIQ code races against hcd_init_fiq() and -the hcd_init_fiq() code races against the outstanding memory stores -from dwc_otg_hcd_init(). Use explicit barriers after touching -driver state. - -usb: dwc_otg: fix memory corruption in dwc_otg driver - -[Upstream commit 51b1b6491752ac066ee8d32cc66042fcc955fef6] - -The move from the staging tree to the main tree exposed a -longstanding memory corruption bug in the dwc2 driver. The -reordering of the driver initialization caused the dwc2 driver -to corrupt the initialization data of the sdhci driver on the -Raspberry Pi platform, which made the bug show up. - -The error is in calling to_usb_device(hsotg->dev), since ->dev -is not a member of struct usb_device. The easiest fix is to -just remove the offending code, since it is not really needed. - -Thanks to Stephen Warren for tracking down the cause of this. - -Reported-by: Andre Heider <a.heider@gmail.com> -Tested-by: Stephen Warren <swarren@wwwdotorg.org> -Signed-off-by: Paul Zimmerman <paulz@synopsys.com> -Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> -[lukas: port from upstream dwc2 to out-of-tree dwc_otg driver] -Signed-off-by: Lukas Wunner <lukas@wunner.de> - -usb: dwb_otg: Fix unreachable switch statement warning - -This warning appears with GCC 7.3.0 from toolchains.bootlin.com: - -../drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c: In function ‘fiq_fsm_update_hs_isoc’: -../drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c:595:61: warning: statement will never be executed [-Wswitch-unreachable] - st->hctsiz_copy.b.xfersize = nrpackets * st->hcchar_copy.b.mps; - ~~~~~~~~~~~~~~~~~^~~~ - -Signed-off-by: Nathan Chancellor <natechancellor@gmail.com> - -dwc_otg: fiq_fsm: fix incorrect DMA register offset calculation - -Rationalise the offset and update all call sites. - -Fixes https://github.com/raspberrypi/linux/issues/2408 - -dwc_otg: fix bug with port_addr assignment for single-TT hubs - -See https://github.com/raspberrypi/linux/issues/2734 - -The "Hub Port" field in the split transaction packet was always set -to 1 for single-TT hubs. The majority of single-TT hub products -apparently ignore this field and broadcast to all downstream enabled -ports, which masked the issue. A subset of hub devices apparently -need the port number to be exact or split transactions will fail. - -usb: dwc_otg: Clean up build warnings on 64bit kernels - -No functional changes. Almost all are changes to logging lines. - -Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org> - -usb: dwc_otg: Use dma allocation for mphi dummy_send buffer - -The FIQ driver used a kzalloc'ed buffer for dummy_send, -passing a kernel virtual address to the hardware block. -The buffer is only ever used for a dummy read, so it -should be harmless, but there is the chance that it will -cause exceptions. - -Use a dma allocation so that we have a genuine bus address, -and read from that. -Free the allocation when done for good measure. - -Signed-off-by: Dave Stevenson <dave.stevenson@raspberrypi.org> - -dwc_otg: only do_split when we actually need to do a split - -The previous test would fail if the root port was in fullspeed mode -and there was a hub between the FS device and the root port. While -the transfer worked, the schedule mangling performed for high-speed -split transfers would break leading to an 8ms polling interval. - -dwc_otg: fix locking around dequeueing and killing URBs - -kill_urbs_in_qh_list() is practically only ever called with the fiq lock -already held, so don't spinlock twice in the case where we need to cancel -an isochronous transfer. - -Also fix up a case where the global interrupt register could be read with -the fiq lock not held. - -Fixes the deadlock seen in https://github.com/raspberrypi/linux/issues/2907 ---- - arch/arm/include/asm/irqflags.h | 16 +- - arch/arm/kernel/fiqasm.S | 4 + - drivers/usb/Makefile | 1 + - drivers/usb/core/generic.c | 1 + - drivers/usb/core/hub.c | 2 +- - drivers/usb/core/message.c | 79 + - drivers/usb/core/otg_whitelist.h | 114 +- - drivers/usb/gadget/file_storage.c | 3676 +++++++++ - drivers/usb/host/Kconfig | 10 + - drivers/usb/host/Makefile | 2 + - drivers/usb/host/dwc_common_port/Makefile | 58 + - .../usb/host/dwc_common_port/Makefile.fbsd | 17 + - .../usb/host/dwc_common_port/Makefile.linux | 49 + - drivers/usb/host/dwc_common_port/changes.txt | 174 + - .../usb/host/dwc_common_port/doc/doxygen.cfg | 270 + - drivers/usb/host/dwc_common_port/dwc_cc.c | 532 ++ - drivers/usb/host/dwc_common_port/dwc_cc.h | 224 + - .../host/dwc_common_port/dwc_common_fbsd.c | 1308 +++ - .../host/dwc_common_port/dwc_common_linux.c | 1409 ++++ - .../host/dwc_common_port/dwc_common_nbsd.c | 1275 +++ - drivers/usb/host/dwc_common_port/dwc_crypto.c | 308 + - drivers/usb/host/dwc_common_port/dwc_crypto.h | 111 + - drivers/usb/host/dwc_common_port/dwc_dh.c | 291 + - drivers/usb/host/dwc_common_port/dwc_dh.h | 106 + - drivers/usb/host/dwc_common_port/dwc_list.h | 594 ++ - drivers/usb/host/dwc_common_port/dwc_mem.c | 245 + - drivers/usb/host/dwc_common_port/dwc_modpow.c | 636 ++ - drivers/usb/host/dwc_common_port/dwc_modpow.h | 34 + - .../usb/host/dwc_common_port/dwc_notifier.c | 319 + - .../usb/host/dwc_common_port/dwc_notifier.h | 122 + - drivers/usb/host/dwc_common_port/dwc_os.h | 1276 +++ - drivers/usb/host/dwc_common_port/usb.h | 946 +++ - drivers/usb/host/dwc_otg/Makefile | 82 + - drivers/usb/host/dwc_otg/doc/doxygen.cfg | 224 + - drivers/usb/host/dwc_otg/dummy_audio.c | 1574 ++++ - drivers/usb/host/dwc_otg/dwc_cfi_common.h | 142 + - drivers/usb/host/dwc_otg/dwc_otg_adp.c | 854 ++ - drivers/usb/host/dwc_otg/dwc_otg_adp.h | 80 + - drivers/usb/host/dwc_otg/dwc_otg_attr.c | 1212 +++ - drivers/usb/host/dwc_otg/dwc_otg_attr.h | 89 + - drivers/usb/host/dwc_otg/dwc_otg_cfi.c | 1876 +++++ - drivers/usb/host/dwc_otg/dwc_otg_cfi.h | 320 + - drivers/usb/host/dwc_otg/dwc_otg_cil.c | 7146 +++++++++++++++++ - drivers/usb/host/dwc_otg/dwc_otg_cil.h | 1464 ++++ - drivers/usb/host/dwc_otg/dwc_otg_cil_intr.c | 1601 ++++ - drivers/usb/host/dwc_otg/dwc_otg_core_if.h | 705 ++ - drivers/usb/host/dwc_otg/dwc_otg_dbg.h | 117 + - drivers/usb/host/dwc_otg/dwc_otg_driver.c | 1766 ++++ - drivers/usb/host/dwc_otg/dwc_otg_driver.h | 86 + - drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.c | 1401 ++++ - drivers/usb/host/dwc_otg/dwc_otg_fiq_fsm.h | 373 + - drivers/usb/host/dwc_otg/dwc_otg_fiq_stub.S | 80 + - drivers/usb/host/dwc_otg/dwc_otg_hcd.c | 4305 ++++++++++ - drivers/usb/host/dwc_otg/dwc_otg_hcd.h | 870 ++ - drivers/usb/host/dwc_otg/dwc_otg_hcd_ddma.c | 1134 +++ - drivers/usb/host/dwc_otg/dwc_otg_hcd_if.h | 417 + - drivers/usb/host/dwc_otg/dwc_otg_hcd_intr.c | 2752 +++++++ - drivers/usb/host/dwc_otg/dwc_otg_hcd_linux.c | 1000 +++ - drivers/usb/host/dwc_otg/dwc_otg_hcd_queue.c | 970 +++ - drivers/usb/host/dwc_otg/dwc_otg_os_dep.h | 188 + - drivers/usb/host/dwc_otg/dwc_otg_pcd.c | 2725 +++++++ - drivers/usb/host/dwc_otg/dwc_otg_pcd.h | 273 + - drivers/usb/host/dwc_otg/dwc_otg_pcd_if.h | 361 + - drivers/usb/host/dwc_otg/dwc_otg_pcd_intr.c | 5148 ++++++++++++ - drivers/usb/host/dwc_otg/dwc_otg_pcd_linux.c | 1280 +++ - drivers/usb/host/dwc_otg/dwc_otg_regs.h | 2550 ++++++ - drivers/usb/host/dwc_otg/test/Makefile | 16 + - drivers/usb/host/dwc_otg/test/dwc_otg_test.pm | 337 + - .../usb/host/dwc_otg/test/test_mod_param.pl | 133 + - drivers/usb/host/dwc_otg/test/test_sysfs.pl | 193 + - 70 files changed, 60037 insertions(+), 16 deletions(-) - -diff --git a/arch/arm/include/asm/irqflags.h b/arch/arm/include/asm/irqflags.h -index aeec7f24eb75..a3b186608c60 100644 ---- a/arch/arm/include/asm/irqflags.h -+++ b/arch/arm/include/asm/irqflags.h -@@ -163,13 +163,23 @@ static inline unsigned long arch_local_save_flags(void) - } - - /* -- * restore saved IRQ & FIQ state -+ * restore saved IRQ state - */ - #define arch_local_irq_restore arch_local_irq_restore - static inline void arch_local_irq_restore(unsigned long flags) - { -- asm volatile( -- " msr " IRQMASK_REG_NAME_W ", %0 @ local_irq_restore" -+ unsigned long temp = 0; -+ flags &= ~(1 << 6); -+ asm volatile ( -+ " mrs %0, cpsr" -+ : "=r" (temp) -+ : -+ : "memory", "cc"); -+ /* Preserve FIQ bit */ -+ temp &= (1 << 6); -+ flags = flags | temp; -+ asm volatile ( -+ " msr cpsr_c, %0 @ local_irq_restore" - : - : "r" (flags) - : "memory", "cc"); -diff --git a/arch/arm/kernel/fiqasm.S b/arch/arm/kernel/fiqasm.S -index 8dd26e1a9bd6..eef484756af2 100644 ---- a/arch/arm/kernel/fiqasm.S -+++ b/arch/arm/kernel/fiqasm.S -@@ -47,3 +47,7 @@ ENTRY(__get_fiq_regs) - mov r0, r0 @ avoid hazard prior to ARMv4 - ret lr - ENDPROC(__get_fiq_regs) -+ -+ENTRY(__FIQ_Branch) -+ mov pc, r8 -+ENDPROC(__FIQ_Branch) -diff --git a/drivers/usb/Makefile b/drivers/usb/Makefile -index 7d1b8c82b208..2810d7153f57 100644 ---- a/drivers/usb/Makefile -+++ b/drivers/usb/Makefile -@@ -8,6 +8,7 @@ - obj-$(CONFIG_USB) += core/ - obj-$(CONFIG_USB_SUPPORT) += phy/ - -+obj-$(CONFIG_USB_DWCOTG) += host/ - obj-$(CONFIG_USB_DWC3) += dwc3/ - obj-$(CONFIG_USB_DWC2) += dwc2/ - obj-$(CONFIG_USB_ISP1760) += isp1760/ -diff --git a/drivers/usb/core/generic.c b/drivers/usb/core/generic.c -index f713cecc1f41..72bf1da12a52 100644 ---- a/drivers/usb/core/generic.c -+++ b/drivers/usb/core/generic.c -@@ -184,6 +184,7 @@ int usb_choose_configuration(struct usb_device *udev) - dev_warn(&udev->dev, - "no configuration chosen from %d choice%s\n", - num_configs, plural(num_configs)); -+ dev_warn(&udev->dev, "No support over %dmA\n", udev->bus_mA); - } - return i; - } -diff --git a/drivers/usb/core/hub.c b/drivers/usb/core/hub.c -index d325dd66f10e..2bbaf83e9b79 100644 ---- a/drivers/usb/core/hub.c -+++ b/drivers/usb/core/hub.c -@@ -5248,7 +5248,7 @@ static void port_event(struct usb_hub *hub, int port1) - port_dev->over_current_count++; - port_over_current_notify(port_dev); - -- dev_dbg(&port_dev->dev, "over-current change #%u\n", -+ dev_notice(&port_dev->dev, "over-current change #%u\n", - port_dev->over_current_count); - usb_clear_port_feature(hdev, port1, - USB_PORT_FEAT_C_OVER_CURRENT); -diff --git a/drivers/usb/core/message.c b/drivers/usb/core/message.c -index 4020ce8db6ce..9b5411635f96 100644 ---- a/drivers/usb/core/message.c -+++ b/drivers/usb/core/message.c -@@ -1993,6 +1993,85 @@ int usb_set_configuration(struct usb_device *dev, int configuration) - if (cp->string == NULL && - !(dev->quirks & USB_QUIRK_CONFIG_INTF_STRINGS)) - cp->string = usb_cache_string(dev, cp->desc.iConfiguration); -+/* Uncomment this define to enable the HS Electrical Test support */ -+#define DWC_HS_ELECT_TST 1 -+#ifdef DWC_HS_ELECT_TST -+ /* Here we implement the HS Electrical Test support. The -+ * tester uses a vendor ID of 0x1A0A to indicate we should -+ * run a special test sequence. The product ID tells us -+ * which sequence to run. We invoke the test sequence by -+ * sending a non-standard SetFeature command to our root -+ * hub port. Our dwc_otg_hcd_hub_control() routine will -+ * recognize the command and perform the desired test -+ * sequence. -+ */ -+ if (dev->descriptor.idVendor == 0x1A0A) { -+ /* HSOTG Electrical Test */ -+ dev_warn(&dev->dev, "VID from HSOTG Electrical Test Fixture\n"); -+ -+ if (dev->bus && dev->bus->root_hub) { -+ struct usb_device *hdev = dev->bus->root_hub; -+ dev_warn(&dev->dev, "Got PID 0x%x\n", dev->descriptor.idProduct); -+ -+ switch (dev->descriptor.idProduct) { -+ case 0x0101: /* TEST_SE0_NAK */ -+ dev_warn(&dev->dev, "TEST_SE0_NAK\n"); -+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), -+ USB_REQ_SET_FEATURE, USB_RT_PORT, -+ USB_PORT_FEAT_TEST, 0x300, NULL, 0, HZ); -+ break; -+ -+ case 0x0102: /* TEST_J */ -+ dev_warn(&dev->dev, "TEST_J\n"); -+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), -+ USB_REQ_SET_FEATURE, USB_RT_PORT, -+ USB_PORT_FEAT_TEST, 0x100, NULL, 0, HZ); -+ break; -+ -+ case 0x0103: /* TEST_K */ -+ dev_warn(&dev->dev, "TEST_K\n"); -+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), -+ USB_REQ_SET_FEATURE, USB_RT_PORT, -+ USB_PORT_FEAT_TEST, 0x200, NULL, 0, HZ); -+ break; -+ -+ case 0x0104: /* TEST_PACKET */ -+ dev_warn(&dev->dev, "TEST_PACKET\n"); -+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), -+ USB_REQ_SET_FEATURE, USB_RT_PORT, -+ USB_PORT_FEAT_TEST, 0x400, NULL, 0, HZ); -+ break; -+ -+ case 0x0105: /* TEST_FORCE_ENABLE */ -+ dev_warn(&dev->dev, "TEST_FORCE_ENABLE\n"); -+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), -+ USB_REQ_SET_FEATURE, USB_RT_PORT, -+ USB_PORT_FEAT_TEST, 0x500, NULL, 0, HZ); -+ break; -+ -+ case 0x0106: /* HS_HOST_PORT_SUSPEND_RESUME */ -+ dev_warn(&dev->dev, "HS_HOST_PORT_SUSPEND_RESUME\n"); -+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), -+ USB_REQ_SET_FEATURE, USB_RT_PORT, -+ USB_PORT_FEAT_TEST, 0x600, NULL, 0, 40 * HZ); -+ break; -+ -+ case 0x0107: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup */ -+ dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR setup\n"); -+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), -+ USB_REQ_SET_FEATURE, USB_RT_PORT, -+ USB_PORT_FEAT_TEST, 0x700, NULL, 0, 40 * HZ); -+ break; -+ -+ case 0x0108: /* SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute */ -+ dev_warn(&dev->dev, "SINGLE_STEP_GET_DEVICE_DESCRIPTOR execute\n"); -+ usb_control_msg(hdev, usb_sndctrlpipe(hdev, 0), -+ USB_REQ_SET_FEATURE, USB_RT_PORT, -+ USB_PORT_FEAT_TEST, 0x800, NULL, 0, 40 * HZ); -+ } -+ } -+ } -+#endif /* DWC_HS_ELECT_TST */ - - /* Now that the interfaces are installed, re-enable LPM. */ - usb_unlocked_enable_lpm(dev); -diff --git a/drivers/usb/core/otg_whitelist.h b/drivers/usb/core/otg_whitelist.h -index 2ae90158ded7..150d4fa1e09b 100644 ---- a/drivers/usb/core/otg_whitelist.h -+++ b/drivers/usb/core/otg_whitelist.h -@@ -15,33 +15,82 @@ - static struct usb_device_id whitelist_table[] = { - - /* hubs are optional in OTG, but very handy ... */ -+#define CERT_WITHOUT_HUBS -+#if defined(CERT_WITHOUT_HUBS) -+{ USB_DEVICE( 0x0000, 0x0000 ), }, /* Root HUB Only*/ -+#else - { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 0), }, - { USB_DEVICE_INFO(USB_CLASS_HUB, 0, 1), }, -+{ USB_DEVICE_INFO(USB_CLASS_HUB, 0, 2), }, -+#endif - - #ifdef CONFIG_USB_PRINTER /* ignoring nonstatic linkage! */ - /* FIXME actually, printers are NOT supposed to use device classes; - * they're supposed to use interface classes... - */ --{ USB_DEVICE_INFO(7, 1, 1) }, --{ USB_DEVICE_INFO(7, 1, 2) }, --{ USB_DEVICE_INFO(7, 1, 3) }, -+//{ USB_DEVICE_INFO(7, 1, 1) }, -+//{ USB_DEVICE_INFO(7, 1, 2) }, -+//{ USB_DEVICE_INFO(7, 1, 3) }, - #endif - - #ifdef CONFIG_USB_NET_CDCETHER - /* Linux-USB CDC Ethernet gadget */ --{ USB_DEVICE(0x0525, 0xa4a1), }, -+//{ USB_DEVICE(0x0525, 0xa4a1), }, - /* Linux-USB CDC Ethernet + RNDIS gadget */ --{ USB_DEVICE(0x0525, 0xa4a2), }, -+//{ USB_DEVICE(0x0525, 0xa4a2), }, - #endif - - #if IS_ENABLED(CONFIG_USB_TEST) - /* gadget zero, for testing */ --{ USB_DEVICE(0x0525, 0xa4a0), }, -+//{ USB_DEVICE(0x0525, 0xa4a0), }, - #endif - -+/* OPT Tester */ -+{ USB_DEVICE( 0x1a0a, 0x0101 ), }, /* TEST_SE0_NAK */ -+{ USB_DEVICE( 0x1a0a, 0x0102 ), }, /* Test_J */ -+{ USB_DEVICE( 0x1a0a, 0x0103 ), }, /* Test_K */ -+{ USB_DEVICE( 0x1a0a, 0x0104 ), }, /* Test_PACKET */ -+{ USB_DEVICE( 0x1a0a, 0x0105 ), }, /* Test_FORCE_ENABLE */ -+{ USB_DEVICE( 0x1a0a, 0x0106 ), }, /* HS_PORT_SUSPEND_RESUME */ -+{ USB_DEVICE( 0x1a0a, 0x0107 ), }, /* SINGLE_STEP_GET_DESCRIPTOR setup */ -+{ USB_DEVICE( 0x1a0a, 0x0108 ), }, /* SINGLE_STEP_GET_DESCRIPTOR execute */ -+ -+/* Sony cameras */ -+{ USB_DEVICE_VER(0x054c,0x0010,0x0410, 0x0500), }, -+ -+/* Memory Devices */ -+//{ USB_DEVICE( 0x0781, 0x5150 ), }, /* SanDisk */ -+//{ USB_DEVICE( 0x05DC, 0x0080 ), }, /* Lexar */ -+//{ USB_DEVICE( 0x4146, 0x9281 ), }, /* IOMEGA */ -+//{ USB_DEVICE( 0x067b, 0x2507 ), }, /* Hammer 20GB External HD */ -+{ USB_DEVICE( 0x0EA0, 0x2168 ), }, /* Ours Technology Inc. (BUFFALO ClipDrive)*/ -+//{ USB_DEVICE( 0x0457, 0x0150 ), }, /* Silicon Integrated Systems Corp. */ -+ -+/* HP Printers */ -+//{ USB_DEVICE( 0x03F0, 0x1102 ), }, /* HP Photosmart 245 */ -+//{ USB_DEVICE( 0x03F0, 0x1302 ), }, /* HP Photosmart 370 Series */ -+ -+/* Speakers */ -+//{ USB_DEVICE( 0x0499, 0x3002 ), }, /* YAMAHA YST-MS35D USB Speakers */ -+//{ USB_DEVICE( 0x0672, 0x1041 ), }, /* Labtec USB Headset */ -+ - { } /* Terminating entry */ - }; - -+static inline void report_errors(struct usb_device *dev) -+{ -+ /* OTG MESSAGE: report errors here, customize to match your product */ -+ dev_info(&dev->dev, "device Vendor:%04x Product:%04x is not supported\n", -+ le16_to_cpu(dev->descriptor.idVendor), -+ le16_to_cpu(dev->descriptor.idProduct)); -+ if (USB_CLASS_HUB == dev->descriptor.bDeviceClass){ -+ dev_printk(KERN_CRIT, &dev->dev, "Unsupported Hub Topology\n"); -+ } else { -+ dev_printk(KERN_CRIT, &dev->dev, "Attached Device is not Supported\n"); -+ } -+} -+ -+ - static int is_targeted(struct usb_device *dev) - { - struct usb_device_id *id = whitelist_table; -@@ -91,16 +140,57 @@ static int is_targeted(struct usb_device *dev) - continue; - - return 1; -+ /* NOTE: can't use usb_match_id() since interface caches -+ * aren't set up yet. this is cut/paste from that code. -+ */ -+ for (id = whitelist_table; id->match_flags; id++) { -+#ifdef DEBUG -+ dev_dbg(&dev->dev, -+ "ID: V:%04x P:%04x DC:%04x SC:%04x PR:%04x \n", -+ id->idVendor, -+ id->idProduct, -+ id->bDeviceClass, -+ id->bDeviceSubClass, -+ id->bDeviceProtocol); -+#endif -+ -+ if ((id->match_flags & USB_DEVICE_ID_MATCH_VENDOR) && -+ id->idVendor != le16_to_cpu(dev->descriptor.idVendor)) -+ continue; -+ -+ if ((id->match_flags & USB_DEVICE_ID_MATCH_PRODUCT) && -+ id->idProduct != le16_to_cpu(dev->descriptor.idProduct)) -+ continue; -+ -+ /* No need to test id->bcdDevice_lo != 0, since 0 is never -+ greater than any unsigned number. */ -+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_LO) && -+ (id->bcdDevice_lo > le16_to_cpu(dev->descriptor.bcdDevice))) -+ continue; -+ -+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_HI) && -+ (id->bcdDevice_hi < le16_to_cpu(dev->descriptor.bcdDevice))) -+ continue; -+ -+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_CLASS) && -+ (id->bDeviceClass != dev->descriptor.bDeviceClass)) -+ continue; -+ -+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_SUBCLASS) && -+ (id->bDeviceSubClass != dev->descriptor.bDeviceSubClass)) -+ continue; -+ -+ if ((id->match_flags & USB_DEVICE_ID_MATCH_DEV_PROTOCOL) && -+ (id->bDeviceProtocol != dev->descriptor.bDeviceProtocol)) -+ continue; -+ -+ return 1; -+ } - } - - /* add other match criteria here ... */ - -- -- /* OTG MESSAGE: report errors here, customize to match your product */ -- dev_err(&dev->dev, "device v%04x p%04x is not supported\n", -- le16_to_cpu(dev->descriptor.idVendor), -- le16_to_cpu(dev->descriptor.idProduct)); -- -+ report_errors(dev); - return 0; - } - -diff --git a/drivers/usb/gadget/file_storage.c b/drivers/usb/gadget/file_storage.c -new file mode 100644 -index 000000000000..a896d73f7a93 ---- /dev/null -+++ b/drivers/usb/gadget/file_storage.c -@@ -0,0 +1,3676 @@ -+/* -+ * file_storage.c -- File-backed USB Storage Gadget, for USB development -+ * -+ * Copyright (C) 2003-2008 Alan Stern -+ * All rights reserved. -+ * -+ * Redistribution and use in source and binary forms, with or without -+ * modification, are permitted provided that the following conditions -+ * are met: -+ * 1. Redistributions of source code must retain the above copyright -+ * notice, this list of conditions, and the following disclaimer, -+ * without modification. -+ * 2. Redistributions in binary form must reproduce the above copyright -+ * notice, this list of conditions and the following disclaimer in the -+ * documentation and/or other materials provided with the distribution. -+ * 3. The names of the above-listed copyright holders may not be used -+ * to endorse or promote products derived from this software without -+ * specific prior written permission. -+ * -+ * ALTERNATIVELY, this software may be distributed under the terms of the -+ * GNU General Public License ("GPL") as published by the Free Software -+ * Foundation, either version 2 of that License or (at your option) any -+ * later version. -+ * -+ * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS -+ * IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, -+ * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR -+ * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR -+ * CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF -+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING -+ * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS -+ * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. -+ */ -+ -+ -+/* -+ * The File-backed Storage Gadget acts as a USB Mass Storage device, -+ * appearing to the host as a disk drive or as a CD-ROM drive. In addition -+ * to providing an example of a genuinely useful gadget driver for a USB -+ * device, it also illustrates a technique of double-buffering for increased -+ * throughput. Last but not least, it gives an easy way to probe the -+ * behavior of the Mass Storage drivers in a USB host. -+ * -+ * Backing storage is provided by a regular file or a block device, specified -+ * by the "file" module parameter. Access can be limited to read-only by -+ * setting the optional "ro" module parameter. (For CD-ROM emulation, -+ * access is always read-only.) The gadget will indicate that it has -+ * removable media if the optional "removable" module parameter is set. -+ * -+ * The gadget supports the Control-Bulk (CB), Control-Bulk-Interrupt (CBI), -+ * and Bulk-Only (also known as Bulk-Bulk-Bulk or BBB) transports, selected -+ * by the optional "transport" module parameter. It also supports the -+ * following protocols: RBC (0x01), ATAPI or SFF-8020i (0x02), QIC-157 (0c03), -+ * UFI (0x04), SFF-8070i (0x05), and transparent SCSI (0x06), selected by -+ * the optional "protocol" module parameter. In addition, the default -+ * Vendor ID, Product ID, release number and serial number can be overridden. -+ * -+ * There is support for multiple logical units (LUNs), each of which has -+ * its own backing file. The number of LUNs can be set using the optional -+ * "luns" module parameter (anywhere from 1 to 8), and the corresponding -+ * files are specified using comma-separated lists for "file" and "ro". -+ * The default number of LUNs is taken from the number of "file" elements; -+ * it is 1 if "file" is not given. If "removable" is not set then a backing -+ * file must be specified for each LUN. If it is set, then an unspecified -+ * or empty backing filename means the LUN's medium is not loaded. Ideally -+ * each LUN would be settable independently as a disk drive or a CD-ROM -+ * drive, but currently all LUNs have to be the same type. The CD-ROM -+ * emulation includes a single data track and no audio tracks; hence there -+ * need be only one backing file per LUN. -+ * -+ * Requirements are modest; only a bulk-in and a bulk-out endpoint are -+ * needed (an interrupt-out endpoint is also needed for CBI). The memory -+ * requirement amounts to two 16K buffers, size configurable by a parameter. -+ * Support is included for both full-speed and high-speed operation. -+ * -+ * Note that the driver is slightly non-portable in that it assumes a -+ * single memory/DMA buffer will be useable for bulk-in, bulk-out, and -+ * interrupt-in endpoints. With most device controllers this isn't an -+ * issue, but there may be some with hardware restrictions that prevent -+ * a buffer from being used by more than one endpoint. -+ * -+ * Module options: -+ * -+ * file=filename[,filename...] -+ * Required if "removable" is not set, names of -+ * the files or block devices used for -+ * backing storage -+ * serial=HHHH... Required serial number (string of hex chars) -+ * ro=b[,b...] Default false, booleans for read-only access -+ * removable Default false, boolean for removable media -+ * luns=N Default N = number of filenames, number of -+ * LUNs to support -+ * nofua=b[,b...] Default false, booleans for ignore FUA flag -+ * in SCSI WRITE(10,12) commands -+ * stall Default determined according to the type of -+ * USB device controller (usually true), -+ * boolean to permit the driver to halt -+ * bulk endpoints -+ * cdrom Default false, boolean for whether to emulate -+ * a CD-ROM drive -+ * transport=XXX Default BBB, transport name (CB, CBI, or BBB) -+ * protocol=YYY Default SCSI, protocol name (RBC, 8020 or -+ * ATAPI, QIC, UFI, 8070, or SCSI; -+ * also 1 - 6) -+ * vendor=0xVVVV Default 0x0525 (NetChip), USB Vendor ID -+ * product=0xPPPP Default 0xa4a5 (FSG), USB Product ID -+ * release=0xRRRR Override the USB release number (bcdDevice) -+ * buflen=N Default N=16384, buffer size used (will be -+ * rounded down to a multiple of -+ * PAGE_CACHE_SIZE) -+ * -+ * If CONFIG_USB_FILE_STORAGE_TEST is not set, only the "file", "serial", "ro", -+ * "removable", "luns", "nofua", "stall", and "cdrom" options are available; -+ * default values are used for everything else. -+ * -+ * The pathnames of the backing files and the ro settings are available in -+ * the attribute files "file", "nofua", and "ro" in the lun<n> subdirectory of -+ * the gadget's sysfs directory. If the "removable" option is set, writing to -+ * these files will simulate ejecting/loading the medium (writing an empty -+ * line means eject) and adjusting a write-enable tab. Changes to the ro -+ * setting are not allowed when the medium is loaded or if CD-ROM emulation -+ * is being used. -+ * -+ * This gadget driver is heavily based on "Gadget Zero" by David Brownell. -+ * The driver's SCSI command interface was based on the "Information -+ * technology - Small Computer System Interface - 2" document from -+ * X3T9.2 Project 375D, Revision 10L, 7-SEP-93, available at -+ * <http://www.t10.org/ftp/t10/drafts/s2/s2-r10l.pdf>. The single exception -+ * is opcode 0x23 (READ FORMAT CAPACITIES), which was based on the -+ * "Universal Serial Bus Mass Storage Class UFI Command Specification" -+ * document, Revision 1.0, December 14, 1998, available at -+ * <http://www.usb.org/developers/devclass_docs/usbmass-ufi10.pdf>. -+ */ -+ -+ -+/* -+ * Driver Design -+ * -+ * The FSG driver is fairly straightforward. There is a main kernel -+ * thread that handles most of the work. Interrupt routines field -+ * callbacks from the controller driver: bulk- and interrupt-request -+ * completion notifications, endpoint-0 events, and disconnect events. -+ * Completion events are passed to the main thread by wakeup calls. Many -+ * ep0 requests are handled at interrupt time, but SetInterface, -+ * SetConfiguration, and device reset requests are forwarded to the -+ * thread in the form of "exceptions" using SIGUSR1 signals (since they -+ * should interrupt any ongoing file I/O operations). -+ * -+ * The thread's main routine implements the standard command/data/status -+ * parts of a SCSI interaction. It and its subroutines are full of tests -+ * for pending signals/exceptions -- all this polling is necessary since -+ * the kernel has no setjmp/longjmp equivalents. (Maybe this is an -+ * indication that the driver really wants to be running in userspace.) -+ * An important point is that so long as the thread is alive it keeps an -+ * open reference to the backing file. This will prevent unmounting -+ * the backing file's underlying filesystem and could cause problems -+ * during system shutdown, for example. To prevent such problems, the -+ * thread catches INT, TERM, and KILL signals and converts them into -+ * an EXIT exception. -+ * -+ * In normal operation the main thread is started during the gadget's -+ * fsg_bind() callback and stopped during fsg_unbind(). But it can also -+ * exit when it receives a signal, and there's no point leaving the -+ * gadget running when the thread is dead. So just before the thread -+ * exits, it deregisters the gadget driver. This makes things a little -+ * tricky: The driver is deregistered at two places, and the exiting -+ * thread can indirectly call fsg_unbind() which in turn can tell the -+ * thread to exit. The first problem is resolved through the use of the -+ * REGISTERED atomic bitflag; the driver will only be deregistered once. -+ * The second problem is resolved by having fsg_unbind() check -+ * fsg->state; it won't try to stop the thread if the state is already -+ * FSG_STATE_TERMINATED. -+ * -+ * To provide maximum throughput, the driver uses a circular pipeline of -+ * buffer heads (struct fsg_buffhd). In principle the pipeline can be -+ * arbitrarily long; in practice the benefits don't justify having more -+ * than 2 stages (i.e., double buffering). But it helps to think of the -+ * pipeline as being a long one. Each buffer head contains a bulk-in and -+ * a bulk-out request pointer (since the buffer can be used for both -+ * output and input -- directions always are given from the host's -+ * point of view) as well as a pointer to the buffer and various state -+ * variables. -+ * -+ * Use of the pipeline follows a simple protocol. There is a variable -+ * (fsg->next_buffhd_to_fill) that points to the next buffer head to use. -+ * At any time that buffer head may still be in use from an earlier -+ * request, so each buffer head has a state variable indicating whether -+ * it is EMPTY, FULL, or BUSY. Typical use involves waiting for the -+ * buffer head to be EMPTY, filling the buffer either by file I/O or by -+ * USB I/O (during which the buffer head is BUSY), and marking the buffer -+ * head FULL when the I/O is complete. Then the buffer will be emptied -+ * (again possibly by USB I/O, during which it is marked BUSY) and -+ * finally marked EMPTY again (possibly by a completion routine). -+ * -+ * A module parameter tells the driver to avoid stalling the bulk -+ * endpoints wherever the transport specification allows. This is -+ * necessary for some UDCs like the SuperH, which cannot reliably clear a -+ * halt on a bulk endpoint. However, under certain circumstances the -+ * Bulk-only specification requires a stall. In such cases the driver -+ * will halt the endpoint and set a flag indicating that it should clear -+ * the halt in software during the next device reset. Hopefully this -+ * will permit everything to work correctly. Furthermore, although the -+ * specification allows the bulk-out endpoint to halt when the host sends -+ * too much data, implementing this would cause an unavoidable race. -+ * The driver will always use the "no-stall" approach for OUT transfers. -+ * -+ * One subtle point concerns sending status-stage responses for ep0 -+ * requests. Some of these requests, such as device reset, can involve -+ * interrupting an ongoing file I/O operation, which might take an -+ * arbitrarily long time. During that delay the host might give up on -+ * the original ep0 request and issue a new one. When that happens the -+ * driver should not notify the host about completion of the original -+ * request, as the host will no longer be waiting for it. So the driver -+ * assigns to each ep0 request a unique tag, and it keeps track of the -+ * tag value of the request associated with a long-running exception -+ * (device-reset, interface-change, or configuration-change). When the -+ * exception handler is finished, the status-stage response is submitted -+ * only if the current ep0 request tag is equal to the exception request -+ * tag. Thus only the most recently received ep0 request will get a -+ * status-stage response. -+ * -+ * Warning: This driver source file is too long. It ought to be split up -+ * into a header file plus about 3 separate .c files, to handle the details -+ * of the Gadget, USB Mass Storage, and SCSI protocols. -+ */ -+ -+ -+/* #define VERBOSE_DEBUG */ -+/* #define DUMP_MSGS */ -+ -+ -+#include <linux/blkdev.h> -+#include <linux/completion.h> -+#include <linux/dcache.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <linux/fcntl.h> -+#include <linux/file.h> -+#include <linux/fs.h> -+#include <linux/kref.h> -+#include <linux/kthread.h> -+#include <linux/limits.h> -+#include <linux/module.h> -+#include <linux/rwsem.h> -+#include <linux/slab.h> -+#include <linux/spinlock.h> -+#include <linux/string.h> -+#include <linux/freezer.h> -+#include <linux/utsname.h> -+ -+#include <linux/usb/ch9.h> -+#include <linux/usb/gadget.h> -+ -+#include "gadget_chips.h" -+ -+ -+ -+/* -+ * Kbuild is not very cooperative with respect to linking separately -+ * compiled library objects into one module. So for now we won't use -+ * separate compilation ... ensuring init/exit sections work to shrink -+ * the runtime footprint, and giving us at least some parts of what -+ * a "gcc --combine ... part1.c part2.c part3.c ... " build would. -+ */ -+#include "usbstring.c" -+#include "config.c" -+#include "epautoconf.c" -+ -+/*-------------------------------------------------------------------------*/ -+ -+#define DRIVER_DESC "File-backed Storage Gadget" -+#define DRIVER_NAME "g_file_storage" -+#define DRIVER_VERSION "1 September 2010" -+ -+static char fsg_string_manufacturer[64]; -+static const char fsg_string_product[] = DRIVER_DESC; -+static const char fsg_string_config[] = "Self-powered"; -+static const char fsg_string_interface[] = "Mass Storage"; -+ -+ -+#include "storage_common.c" -+ -+ -+MODULE_DESCRIPTION(DRIVER_DESC); -+MODULE_AUTHOR("Alan Stern"); -+MODULE_LICENSE("Dual BSD/GPL"); -+ -+/* -+ * This driver assumes self-powered hardware and has no way for users to -+ * trigger remote wakeup. It uses autoconfiguration to select endpoints -+ * and endpoint addresses. -+ */ -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+ -+/* Encapsulate the module parameter settings */ -+ -+static struct { -+ char *file[FSG_MAX_LUNS]; -+ char *serial; -+ bool ro[FSG_MAX_LUNS]; -+ bool nofua[FSG_MAX_LUNS]; -+ unsigned int num_filenames; -+ unsigned int num_ros; -+ unsigned int num_nofuas; -+ unsigned int nluns; -+ -+ bool removable; -+ bool can_stall; -+ bool cdrom; -+ -+ char *transport_parm; -+ char *protocol_parm; -+ unsigned short vendor; -+ unsigned short product; -+ unsigned short release; -+ unsigned int buflen; -+ -+ int transport_type; -+ char *transport_name; -+ int protocol_type; -+ char *protocol_name; -+ -+} mod_data = { // Default values -+ .transport_parm = "BBB", -+ .protocol_parm = "SCSI", -+ .removable = 0, -+ .can_stall = 1, -+ .cdrom = 0, -+ .vendor = FSG_VENDOR_ID, -+ .product = FSG_PRODUCT_ID, -+ .release = 0xffff, // Use controller chip type -+ .buflen = 16384, -+ }; -+ -+ -+module_param_array_named(file, mod_data.file, charp, &mod_data.num_filenames, -+ S_IRUGO); -+MODULE_PARM_DESC(file, "names of backing files or devices"); -+ -+module_param_named(serial, mod_data.serial, charp, S_IRUGO); -+MODULE_PARM_DESC(serial, "USB serial number"); -+ -+module_param_array_named(ro, mod_data.ro, bool, &mod_data.num_ros, S_IRUGO); -+MODULE_PARM_DESC(ro, "true to force read-only"); -+ -+module_param_array_named(nofua, mod_data.nofua, bool, &mod_data.num_nofuas, -+ S_IRUGO); -+MODULE_PARM_DESC(nofua, "true to ignore SCSI WRITE(10,12) FUA bit"); -+ -+module_param_named(luns, mod_data.nluns, uint, S_IRUGO); -+MODULE_PARM_DESC(luns, "number of LUNs"); -+ -+module_param_named(removable, mod_data.removable, bool, S_IRUGO); -+MODULE_PARM_DESC(removable, "true to simulate removable media"); -+ -+module_param_named(stall, mod_data.can_stall, bool, S_IRUGO); -+MODULE_PARM_DESC(stall, "false to prevent bulk stalls"); -+ -+module_param_named(cdrom, mod_data.cdrom, bool, S_IRUGO); -+MODULE_PARM_DESC(cdrom, "true to emulate cdrom instead of disk"); -+ -+/* In the non-TEST version, only the module parameters listed above -+ * are available. */ -+#ifdef CONFIG_USB_FILE_STORAGE_TEST -+ -+module_param_named(transport, mod_data.transport_parm, charp, S_IRUGO); -+MODULE_PARM_DESC(transport, "type of transport (BBB, CBI, or CB)"); -+ -+module_param_named(protocol, mod_data.protocol_parm, charp, S_IRUGO); -+MODULE_PARM_DESC(protocol, "type of protocol (RBC, 8020, QIC, UFI, " -+ "8070, or SCSI)"); -+ -+module_param_named(vendor, mod_data.vendor, ushort, S_IRUGO); -+MODULE_PARM_DESC(vendor, "USB Vendor ID"); -+ -+module_param_named(product, mod_data.product, ushort, S_IRUGO); -+MODULE_PARM_DESC(product, "USB Product ID"); -+ -+module_param_named(release, mod_data.release, ushort, S_IRUGO); -+MODULE_PARM_DESC(release, "USB release number"); -+ -+module_param_named(buflen, mod_data.buflen, uint, S_IRUGO); -+MODULE_PARM_DESC(buflen, "I/O buffer size"); -+ -+#endif /* CONFIG_USB_FILE_STORAGE_TEST */ -+ -+ -+/* -+ * These definitions will permit the compiler to avoid generating code for -+ * parts of the driver that aren't used in the non-TEST version. Even gcc -+ * can recognize when a test of a constant expression yields a dead code -+ * path. -+ */ -+ -+#ifdef CONFIG_USB_FILE_STORAGE_TEST -+ -+#define transport_is_bbb() (mod_data.transport_type == USB_PR_BULK) -+#define transport_is_cbi() (mod_data.transport_type == USB_PR_CBI) -+#define protocol_is_scsi() (mod_data.protocol_type == USB_SC_SCSI) -+ -+#else -+ -+#define transport_is_bbb() 1 -+#define transport_is_cbi() 0 -+#define protocol_is_scsi() 1 -+ -+#endif /* CONFIG_USB_FILE_STORAGE_TEST */ -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+ -+struct fsg_dev { -+ /* lock protects: state, all the req_busy's, and cbbuf_cmnd */ -+ spinlock_t lock; -+ struct usb_gadget *gadget; -+ -+ /* filesem protects: backing files in use */ -+ struct rw_semaphore filesem; -+ -+ /* reference counting: wait until all LUNs are released */ -+ struct kref ref; -+ -+ struct usb_ep *ep0; // Handy copy of gadget->ep0 -+ struct usb_request *ep0req; // For control responses -+ unsigned int ep0_req_tag; -+ const char *ep0req_name; -+ -+ struct usb_request *intreq; // For interrupt responses -+ int intreq_busy; -+ struct fsg_buffhd *intr_buffhd; -+ -+ unsigned int bulk_out_maxpacket; -+ enum fsg_state state; // For exception handling -+ unsigned int exception_req_tag; -+ -+ u8 config, new_config; -+ -+ unsigned int running : 1; -+ unsigned int bulk_in_enabled : 1; -+ unsigned int bulk_out_enabled : 1; -+ unsigned int intr_in_enabled : 1; -+ unsigned int phase_error : 1; -+ unsigned int short_packet_received : 1; -+ unsigned int bad_lun_okay : 1; -+ -+ unsigned long atomic_bitflags; -+#define REGISTERED 0 -+#define IGNORE_BULK_OUT 1 -+#define SUSPENDED 2 -+ -+ struct usb_ep *bulk_in; -+ struct usb_ep *bulk_out; -+ struct usb_ep *intr_in; -+ -+ struct fsg_buffhd *next_buffhd_to_fill; -+ struct fsg_buffhd *next_buffhd_to_drain; -+ -+ int thread_wakeup_needed; -+ struct completion thread_notifier; -+ struct task_struct *thread_task; -+ -+ int cmnd_size; -+ u8 cmnd[MAX_COMMAND_SIZE]; -+ enum data_direction data_dir; -+ u32 data_size; -+ u32 data_size_from_cmnd; -+ u32 tag; -+ unsigned int lun; -+ u32 residue; -+ u32 usb_amount_left; -+ -+ /* The CB protocol offers no way for a host to know when a command -+ * has completed. As a result the next command may arrive early, -+ * and we will still have to handle it. For that reason we need -+ * a buffer to store new commands when using CB (or CBI, which -+ * does not oblige a host to wait for command completion either). */ -+ int cbbuf_cmnd_size; -+ u8 cbbuf_cmnd[MAX_COMMAND_SIZE]; -+ -+ unsigned int nluns; -+ struct fsg_lun *luns; -+ struct fsg_lun *curlun; -+ /* Must be the last entry */ -+ struct fsg_buffhd buffhds[]; -+}; -+ -+typedef void (*fsg_routine_t)(struct fsg_dev *); -+ -+static int exception_in_progress(struct fsg_dev *fsg) -+{ -+ return (fsg->state > FSG_STATE_IDLE); -+} -+ -+/* Make bulk-out requests be divisible by the maxpacket size */ -+static void set_bulk_out_req_length(struct fsg_dev *fsg, -+ struct fsg_buffhd *bh, unsigned int length) -+{ -+ unsigned int rem; -+ -+ bh->bulk_out_intended_length = length; -+ rem = length % fsg->bulk_out_maxpacket; -+ if (rem > 0) -+ length += fsg->bulk_out_maxpacket - rem; -+ bh->outreq->length = length; -+} -+ -+static struct fsg_dev *the_fsg; -+static struct usb_gadget_driver fsg_driver; -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int fsg_set_halt(struct fsg_dev *fsg, struct usb_ep *ep) -+{ -+ const char *name; -+ -+ if (ep == fsg->bulk_in) -+ name = "bulk-in"; -+ else if (ep == fsg->bulk_out) -+ name = "bulk-out"; -+ else -+ name = ep->name; -+ DBG(fsg, "%s set halt\n", name); -+ return usb_ep_set_halt(ep); -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* -+ * DESCRIPTORS ... most are static, but strings and (full) configuration -+ * descriptors are built on demand. Also the (static) config and interface -+ * descriptors are adjusted during fsg_bind(). -+ */ -+ -+/* There is only one configuration. */ -+#define CONFIG_VALUE 1 -+ -+static struct usb_device_descriptor -+device_desc = { -+ .bLength = sizeof device_desc, -+ .bDescriptorType = USB_DT_DEVICE, -+ -+ .bcdUSB = cpu_to_le16(0x0200), -+ .bDeviceClass = USB_CLASS_PER_INTERFACE, -+ -+ /* The next three values can be overridden by module parameters */ -+ .idVendor = cpu_to_le16(FSG_VENDOR_ID), -+ .idProduct = cpu_to_le16(FSG_PRODUCT_ID), -+ .bcdDevice = cpu_to_le16(0xffff), -+ -+ .iManufacturer = FSG_STRING_MANUFACTURER, -+ .iProduct = FSG_STRING_PRODUCT, -+ .iSerialNumber = FSG_STRING_SERIAL, -+ .bNumConfigurations = 1, -+}; -+ -+static struct usb_config_descriptor -+config_desc = { -+ .bLength = sizeof config_desc, -+ .bDescriptorType = USB_DT_CONFIG, -+ -+ /* wTotalLength computed by usb_gadget_config_buf() */ -+ .bNumInterfaces = 1, -+ .bConfigurationValue = CONFIG_VALUE, -+ .iConfiguration = FSG_STRING_CONFIG, -+ .bmAttributes = USB_CONFIG_ATT_ONE | USB_CONFIG_ATT_SELFPOWER, -+ .bMaxPower = CONFIG_USB_GADGET_VBUS_DRAW / 2, -+}; -+ -+ -+static struct usb_qualifier_descriptor -+dev_qualifier = { -+ .bLength = sizeof dev_qualifier, -+ .bDescriptorType = USB_DT_DEVICE_QUALIFIER, -+ -+ .bcdUSB = cpu_to_le16(0x0200), -+ .bDeviceClass = USB_CLASS_PER_INTERFACE, -+ -+ .bNumConfigurations = 1, -+}; -+ -+static int populate_bos(struct fsg_dev *fsg, u8 *buf) -+{ -+ memcpy(buf, &fsg_bos_desc, USB_DT_BOS_SIZE); -+ buf += USB_DT_BOS_SIZE; -+ -+ memcpy(buf, &fsg_ext_cap_desc, USB_DT_USB_EXT_CAP_SIZE); -+ buf += USB_DT_USB_EXT_CAP_SIZE; -+ -+ memcpy(buf, &fsg_ss_cap_desc, USB_DT_USB_SS_CAP_SIZE); -+ -+ return USB_DT_BOS_SIZE + USB_DT_USB_SS_CAP_SIZE -+ + USB_DT_USB_EXT_CAP_SIZE; -+} -+ -+/* -+ * Config descriptors must agree with the code that sets configurations -+ * and with code managing interfaces and their altsettings. They must -+ * also handle different speeds and other-speed requests. -+ */ -+static int populate_config_buf(struct usb_gadget *gadget, -+ u8 *buf, u8 type, unsigned index) -+{ -+ enum usb_device_speed speed = gadget->speed; -+ int len; -+ const struct usb_descriptor_header **function; -+ -+ if (index > 0) -+ return -EINVAL; -+ -+ if (gadget_is_dualspeed(gadget) && type == USB_DT_OTHER_SPEED_CONFIG) -+ speed = (USB_SPEED_FULL + USB_SPEED_HIGH) - speed; -+ function = gadget_is_dualspeed(gadget) && speed == USB_SPEED_HIGH -+ ? (const struct usb_descriptor_header **)fsg_hs_function -+ : (const struct usb_descriptor_header **)fsg_fs_function; -+ -+ /* for now, don't advertise srp-only devices */ -+ if (!gadget_is_otg(gadget)) -+ function++; -+ -+ len = usb_gadget_config_buf(&config_desc, buf, EP0_BUFSIZE, function); -+ ((struct usb_config_descriptor *) buf)->bDescriptorType = type; -+ return len; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* These routines may be called in process context or in_irq */ -+ -+/* Caller must hold fsg->lock */ -+static void wakeup_thread(struct fsg_dev *fsg) -+{ -+ /* Tell the main thread that something has happened */ -+ fsg->thread_wakeup_needed = 1; -+ if (fsg->thread_task) -+ wake_up_process(fsg->thread_task); -+} -+ -+ -+static void raise_exception(struct fsg_dev *fsg, enum fsg_state new_state) -+{ -+ unsigned long flags; -+ -+ /* Do nothing if a higher-priority exception is already in progress. -+ * If a lower-or-equal priority exception is in progress, preempt it -+ * and notify the main thread by sending it a signal. */ -+ spin_lock_irqsave(&fsg->lock, flags); -+ if (fsg->state <= new_state) { -+ fsg->exception_req_tag = fsg->ep0_req_tag; -+ fsg->state = new_state; -+ if (fsg->thread_task) -+ send_sig_info(SIGUSR1, SEND_SIG_FORCED, -+ fsg->thread_task); -+ } -+ spin_unlock_irqrestore(&fsg->lock, flags); -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* The disconnect callback and ep0 routines. These always run in_irq, -+ * except that ep0_queue() is called in the main thread to acknowledge -+ * completion of various requests: set config, set interface, and -+ * Bulk-only device reset. */ -+ -+static void fsg_disconnect(struct usb_gadget *gadget) -+{ -+ struct fsg_dev *fsg = get_gadget_data(gadget); -+ -+ DBG(fsg, "disconnect or port reset\n"); -+ raise_exception(fsg, FSG_STATE_DISCONNECT); -+} -+ -+ -+static int ep0_queue(struct fsg_dev *fsg) -+{ -+ int rc; -+ -+ rc = usb_ep_queue(fsg->ep0, fsg->ep0req, GFP_ATOMIC); -+ if (rc != 0 && rc != -ESHUTDOWN) { -+ -+ /* We can't do much more than wait for a reset */ -+ WARNING(fsg, "error in submission: %s --> %d\n", -+ fsg->ep0->name, rc); -+ } -+ return rc; -+} -+ -+static void ep0_complete(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct fsg_dev *fsg = ep->driver_data; -+ -+ if (req->actual > 0) -+ dump_msg(fsg, fsg->ep0req_name, req->buf, req->actual); -+ if (req->status || req->actual != req->length) -+ DBG(fsg, "%s --> %d, %u/%u\n", __func__, -+ req->status, req->actual, req->length); -+ if (req->status == -ECONNRESET) // Request was cancelled -+ usb_ep_fifo_flush(ep); -+ -+ if (req->status == 0 && req->context) -+ ((fsg_routine_t) (req->context))(fsg); -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* Bulk and interrupt endpoint completion handlers. -+ * These always run in_irq. */ -+ -+static void bulk_in_complete(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct fsg_dev *fsg = ep->driver_data; -+ struct fsg_buffhd *bh = req->context; -+ -+ if (req->status || req->actual != req->length) -+ DBG(fsg, "%s --> %d, %u/%u\n", __func__, -+ req->status, req->actual, req->length); -+ if (req->status == -ECONNRESET) // Request was cancelled -+ usb_ep_fifo_flush(ep); -+ -+ /* Hold the lock while we update the request and buffer states */ -+ smp_wmb(); -+ spin_lock(&fsg->lock); -+ bh->inreq_busy = 0; -+ bh->state = BUF_STATE_EMPTY; -+ wakeup_thread(fsg); -+ spin_unlock(&fsg->lock); -+} -+ -+static void bulk_out_complete(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct fsg_dev *fsg = ep->driver_data; -+ struct fsg_buffhd *bh = req->context; -+ -+ dump_msg(fsg, "bulk-out", req->buf, req->actual); -+ if (req->status || req->actual != bh->bulk_out_intended_length) -+ DBG(fsg, "%s --> %d, %u/%u\n", __func__, -+ req->status, req->actual, -+ bh->bulk_out_intended_length); -+ if (req->status == -ECONNRESET) // Request was cancelled -+ usb_ep_fifo_flush(ep); -+ -+ /* Hold the lock while we update the request and buffer states */ -+ smp_wmb(); -+ spin_lock(&fsg->lock); -+ bh->outreq_busy = 0; -+ bh->state = BUF_STATE_FULL; -+ wakeup_thread(fsg); -+ spin_unlock(&fsg->lock); -+} -+ -+ -+#ifdef CONFIG_USB_FILE_STORAGE_TEST -+static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) -+{ -+ struct fsg_dev *fsg = ep->driver_data; -+ struct fsg_buffhd *bh = req->context; -+ -+ if (req->status || req->actual != req->length) -+ DBG(fsg, "%s --> %d, %u/%u\n", __func__, -+ req->status, req->actual, req->length); -+ if (req->status == -ECONNRESET) // Request was cancelled -+ usb_ep_fifo_flush(ep); -+ -+ /* Hold the lock while we update the request and buffer states */ -+ smp_wmb(); -+ spin_lock(&fsg->lock); -+ fsg->intreq_busy = 0; -+ bh->state = BUF_STATE_EMPTY; -+ wakeup_thread(fsg); -+ spin_unlock(&fsg->lock); -+} -+ -+#else -+static void intr_in_complete(struct usb_ep *ep, struct usb_request *req) -+{} -+#endif /* CONFIG_USB_FILE_STORAGE_TEST */ -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* Ep0 class-specific handlers. These always run in_irq. */ -+ -+#ifdef CONFIG_USB_FILE_STORAGE_TEST -+static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -+{ -+ struct usb_request *req = fsg->ep0req; -+ static u8 cbi_reset_cmnd[6] = { -+ SEND_DIAGNOSTIC, 4, 0xff, 0xff, 0xff, 0xff}; -+ -+ /* Error in command transfer? */ -+ if (req->status || req->length != req->actual || -+ req->actual < 6 || req->actual > MAX_COMMAND_SIZE) { -+ -+ /* Not all controllers allow a protocol stall after -+ * receiving control-out data, but we'll try anyway. */ -+ fsg_set_halt(fsg, fsg->ep0); -+ return; // Wait for reset -+ } -+ -+ /* Is it the special reset command? */ -+ if (req->actual >= sizeof cbi_reset_cmnd && -+ memcmp(req->buf, cbi_reset_cmnd, -+ sizeof cbi_reset_cmnd) == 0) { -+ -+ /* Raise an exception to stop the current operation -+ * and reinitialize our state. */ -+ DBG(fsg, "cbi reset request\n"); -+ raise_exception(fsg, FSG_STATE_RESET); -+ return; -+ } -+ -+ VDBG(fsg, "CB[I] accept device-specific command\n"); -+ spin_lock(&fsg->lock); -+ -+ /* Save the command for later */ -+ if (fsg->cbbuf_cmnd_size) -+ WARNING(fsg, "CB[I] overwriting previous command\n"); -+ fsg->cbbuf_cmnd_size = req->actual; -+ memcpy(fsg->cbbuf_cmnd, req->buf, fsg->cbbuf_cmnd_size); -+ -+ wakeup_thread(fsg); -+ spin_unlock(&fsg->lock); -+} -+ -+#else -+static void received_cbi_adsc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -+{} -+#endif /* CONFIG_USB_FILE_STORAGE_TEST */ -+ -+ -+static int class_setup_req(struct fsg_dev *fsg, -+ const struct usb_ctrlrequest *ctrl) -+{ -+ struct usb_request *req = fsg->ep0req; -+ int value = -EOPNOTSUPP; -+ u16 w_index = le16_to_cpu(ctrl->wIndex); -+ u16 w_value = le16_to_cpu(ctrl->wValue); -+ u16 w_length = le16_to_cpu(ctrl->wLength); -+ -+ if (!fsg->config) -+ return value; -+ -+ /* Handle Bulk-only class-specific requests */ -+ if (transport_is_bbb()) { -+ switch (ctrl->bRequest) { -+ -+ case US_BULK_RESET_REQUEST: -+ if (ctrl->bRequestType != (USB_DIR_OUT | -+ USB_TYPE_CLASS | USB_RECIP_INTERFACE)) -+ break; -+ if (w_index != 0 || w_value != 0 || w_length != 0) { -+ value = -EDOM; -+ break; -+ } -+ -+ /* Raise an exception to stop the current operation -+ * and reinitialize our state. */ -+ DBG(fsg, "bulk reset request\n"); -+ raise_exception(fsg, FSG_STATE_RESET); -+ value = DELAYED_STATUS; -+ break; -+ -+ case US_BULK_GET_MAX_LUN: -+ if (ctrl->bRequestType != (USB_DIR_IN | -+ USB_TYPE_CLASS | USB_RECIP_INTERFACE)) -+ break; -+ if (w_index != 0 || w_value != 0 || w_length != 1) { -+ value = -EDOM; -+ break; -+ } -+ VDBG(fsg, "get max LUN\n"); -+ *(u8 *) req->buf = fsg->nluns - 1; -+ value = 1; -+ break; -+ } -+ } -+ -+ /* Handle CBI class-specific requests */ -+ else { -+ switch (ctrl->bRequest) { -+ -+ case USB_CBI_ADSC_REQUEST: -+ if (ctrl->bRequestType != (USB_DIR_OUT | -+ USB_TYPE_CLASS | USB_RECIP_INTERFACE)) -+ break; -+ if (w_index != 0 || w_value != 0) { -+ value = -EDOM; -+ break; -+ } -+ if (w_length > MAX_COMMAND_SIZE) { -+ value = -EOVERFLOW; -+ break; -+ } -+ value = w_length; -+ fsg->ep0req->context = received_cbi_adsc; -+ break; -+ } -+ } -+ -+ if (value == -EOPNOTSUPP) -+ VDBG(fsg, -+ "unknown class-specific control req " -+ "%02x.%02x v%04x i%04x l%u\n", -+ ctrl->bRequestType, ctrl->bRequest, -+ le16_to_cpu(ctrl->wValue), w_index, w_length); -+ return value; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* Ep0 standard request handlers. These always run in_irq. */ -+ -+static int standard_setup_req(struct fsg_dev *fsg, -+ const struct usb_ctrlrequest *ctrl) -+{ -+ struct usb_request *req = fsg->ep0req; -+ int value = -EOPNOTSUPP; -+ u16 w_index = le16_to_cpu(ctrl->wIndex); -+ u16 w_value = le16_to_cpu(ctrl->wValue); -+ -+ /* Usually this just stores reply data in the pre-allocated ep0 buffer, -+ * but config change events will also reconfigure hardware. */ -+ switch (ctrl->bRequest) { -+ -+ case USB_REQ_GET_DESCRIPTOR: -+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | -+ USB_RECIP_DEVICE)) -+ break; -+ switch (w_value >> 8) { -+ -+ case USB_DT_DEVICE: -+ VDBG(fsg, "get device descriptor\n"); -+ device_desc.bMaxPacketSize0 = fsg->ep0->maxpacket; -+ value = sizeof device_desc; -+ memcpy(req->buf, &device_desc, value); -+ break; -+ case USB_DT_DEVICE_QUALIFIER: -+ VDBG(fsg, "get device qualifier\n"); -+ if (!gadget_is_dualspeed(fsg->gadget) || -+ fsg->gadget->speed == USB_SPEED_SUPER) -+ break; -+ /* -+ * Assume ep0 uses the same maxpacket value for both -+ * speeds -+ */ -+ dev_qualifier.bMaxPacketSize0 = fsg->ep0->maxpacket; -+ value = sizeof dev_qualifier; -+ memcpy(req->buf, &dev_qualifier, value); -+ break; -+ -+ case USB_DT_OTHER_SPEED_CONFIG: -+ VDBG(fsg, "get other-speed config descriptor\n"); -+ if (!gadget_is_dualspeed(fsg->gadget) || -+ fsg->gadget->speed == USB_SPEED_SUPER) -+ break; -+ goto get_config; -+ case USB_DT_CONFIG: -+ VDBG(fsg, "get configuration descriptor\n"); -+get_config: -+ value = populate_config_buf(fsg->gadget, -+ req->buf, -+ w_value >> 8, -+ w_value & 0xff); -+ break; -+ -+ case USB_DT_STRING: -+ VDBG(fsg, "get string descriptor\n"); -+ -+ /* wIndex == language code */ -+ value = usb_gadget_get_string(&fsg_stringtab, -+ w_value & 0xff, req->buf); -+ break; -+ -+ case USB_DT_BOS: -+ VDBG(fsg, "get bos descriptor\n"); -+ -+ if (gadget_is_superspeed(fsg->gadget)) -+ value = populate_bos(fsg, req->buf); -+ break; -+ } -+ -+ break; -+ -+ /* One config, two speeds */ -+ case USB_REQ_SET_CONFIGURATION: -+ if (ctrl->bRequestType != (USB_DIR_OUT | USB_TYPE_STANDARD | -+ USB_RECIP_DEVICE)) -+ break; -+ VDBG(fsg, "set configuration\n"); -+ if (w_value == CONFIG_VALUE || w_value == 0) { -+ fsg->new_config = w_value; -+ -+ /* Raise an exception to wipe out previous transaction -+ * state (queued bufs, etc) and set the new config. */ -+ raise_exception(fsg, FSG_STATE_CONFIG_CHANGE); -+ value = DELAYED_STATUS; -+ } -+ break; -+ case USB_REQ_GET_CONFIGURATION: -+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | -+ USB_RECIP_DEVICE)) -+ break; -+ VDBG(fsg, "get configuration\n"); -+ *(u8 *) req->buf = fsg->config; -+ value = 1; -+ break; -+ -+ case USB_REQ_SET_INTERFACE: -+ if (ctrl->bRequestType != (USB_DIR_OUT| USB_TYPE_STANDARD | -+ USB_RECIP_INTERFACE)) -+ break; -+ if (fsg->config && w_index == 0) { -+ -+ /* Raise an exception to wipe out previous transaction -+ * state (queued bufs, etc) and install the new -+ * interface altsetting. */ -+ raise_exception(fsg, FSG_STATE_INTERFACE_CHANGE); -+ value = DELAYED_STATUS; -+ } -+ break; -+ case USB_REQ_GET_INTERFACE: -+ if (ctrl->bRequestType != (USB_DIR_IN | USB_TYPE_STANDARD | -+ USB_RECIP_INTERFACE)) -+ break; -+ if (!fsg->config) -+ break; -+ if (w_index != 0) { -+ value = -EDOM; -+ break; -+ } -+ VDBG(fsg, "get interface\n"); -+ *(u8 *) req->buf = 0; -+ value = 1; -+ break; -+ -+ default: -+ VDBG(fsg, -+ "unknown control req %02x.%02x v%04x i%04x l%u\n", -+ ctrl->bRequestType, ctrl->bRequest, -+ w_value, w_index, le16_to_cpu(ctrl->wLength)); -+ } -+ -+ return value; -+} -+ -+ -+static int fsg_setup(struct usb_gadget *gadget, -+ const struct usb_ctrlrequest *ctrl) -+{ -+ struct fsg_dev *fsg = get_gadget_data(gadget); -+ int rc; -+ int w_length = le16_to_cpu(ctrl->wLength); -+ -+ ++fsg->ep0_req_tag; // Record arrival of a new request -+ fsg->ep0req->context = NULL; -+ fsg->ep0req->length = 0; -+ dump_msg(fsg, "ep0-setup", (u8 *) ctrl, sizeof(*ctrl)); -+ -+ if ((ctrl->bRequestType & USB_TYPE_MASK) == USB_TYPE_CLASS) -+ rc = class_setup_req(fsg, ctrl); -+ else -+ rc = standard_setup_req(fsg, ctrl); -+ -+ /* Respond with data/status or defer until later? */ -+ if (rc >= 0 && rc != DELAYED_STATUS) { -+ rc = min(rc, w_length); -+ fsg->ep0req->length = rc; -+ fsg->ep0req->zero = rc < w_length; -+ fsg->ep0req_name = (ctrl->bRequestType & USB_DIR_IN ? -+ "ep0-in" : "ep0-out"); -+ rc = ep0_queue(fsg); -+ } -+ -+ /* Device either stalls (rc < 0) or reports success */ -+ return rc; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* All the following routines run in process context */ -+ -+ -+/* Use this for bulk or interrupt transfers, not ep0 */ -+static void start_transfer(struct fsg_dev *fsg, struct usb_ep *ep, -+ struct usb_request *req, int *pbusy, -+ enum fsg_buffer_state *state) -+{ -+ int rc; -+ -+ if (ep == fsg->bulk_in) -+ dump_msg(fsg, "bulk-in", req->buf, req->length); -+ else if (ep == fsg->intr_in) -+ dump_msg(fsg, "intr-in", req->buf, req->length); -+ -+ spin_lock_irq(&fsg->lock); -+ *pbusy = 1; -+ *state = BUF_STATE_BUSY; -+ spin_unlock_irq(&fsg->lock); -+ rc = usb_ep_queue(ep, req, GFP_KERNEL); -+ if (rc != 0) { -+ *pbusy = 0; -+ *state = BUF_STATE_EMPTY; -+ -+ /* We can't do much more than wait for a reset */ -+ -+ /* Note: currently the net2280 driver fails zero-length -+ * submissions if DMA is enabled. */ -+ if (rc != -ESHUTDOWN && !(rc == -EOPNOTSUPP && -+ req->length == 0)) -+ WARNING(fsg, "error in submission: %s --> %d\n", -+ ep->name, rc); -+ } -+} -+ -+ -+static int sleep_thread(struct fsg_dev *fsg) -+{ -+ int rc = 0; -+ -+ /* Wait until a signal arrives or we are woken up */ -+ for (;;) { -+ try_to_freeze(); -+ set_current_state(TASK_INTERRUPTIBLE); -+ if (signal_pending(current)) { -+ rc = -EINTR; -+ break; -+ } -+ if (fsg->thread_wakeup_needed) -+ break; -+ schedule(); -+ } -+ __set_current_state(TASK_RUNNING); -+ fsg->thread_wakeup_needed = 0; -+ return rc; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int do_read(struct fsg_dev *fsg) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ u32 lba; -+ struct fsg_buffhd *bh; -+ int rc; -+ u32 amount_left; -+ loff_t file_offset, file_offset_tmp; -+ unsigned int amount; -+ ssize_t nread; -+ -+ /* Get the starting Logical Block Address and check that it's -+ * not too big */ -+ if (fsg->cmnd[0] == READ_6) -+ lba = get_unaligned_be24(&fsg->cmnd[1]); -+ else { -+ lba = get_unaligned_be32(&fsg->cmnd[2]); -+ -+ /* We allow DPO (Disable Page Out = don't save data in the -+ * cache) and FUA (Force Unit Access = don't read from the -+ * cache), but we don't implement them. */ -+ if ((fsg->cmnd[1] & ~0x18) != 0) { -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ } -+ if (lba >= curlun->num_sectors) { -+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; -+ return -EINVAL; -+ } -+ file_offset = ((loff_t) lba) << curlun->blkbits; -+ -+ /* Carry out the file reads */ -+ amount_left = fsg->data_size_from_cmnd; -+ if (unlikely(amount_left == 0)) -+ return -EIO; // No default reply -+ -+ for (;;) { -+ -+ /* Figure out how much we need to read: -+ * Try to read the remaining amount. -+ * But don't read more than the buffer size. -+ * And don't try to read past the end of the file. -+ */ -+ amount = min((unsigned int) amount_left, mod_data.buflen); -+ amount = min((loff_t) amount, -+ curlun->file_length - file_offset); -+ -+ /* Wait for the next buffer to become available */ -+ bh = fsg->next_buffhd_to_fill; -+ while (bh->state != BUF_STATE_EMPTY) { -+ rc = sleep_thread(fsg); -+ if (rc) -+ return rc; -+ } -+ -+ /* If we were asked to read past the end of file, -+ * end with an empty buffer. */ -+ if (amount == 0) { -+ curlun->sense_data = -+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; -+ curlun->sense_data_info = file_offset >> curlun->blkbits; -+ curlun->info_valid = 1; -+ bh->inreq->length = 0; -+ bh->state = BUF_STATE_FULL; -+ break; -+ } -+ -+ /* Perform the read */ -+ file_offset_tmp = file_offset; -+ nread = vfs_read(curlun->filp, -+ (char __user *) bh->buf, -+ amount, &file_offset_tmp); -+ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, -+ (unsigned long long) file_offset, -+ (int) nread); -+ if (signal_pending(current)) -+ return -EINTR; -+ -+ if (nread < 0) { -+ LDBG(curlun, "error in file read: %d\n", -+ (int) nread); -+ nread = 0; -+ } else if (nread < amount) { -+ LDBG(curlun, "partial file read: %d/%u\n", -+ (int) nread, amount); -+ nread = round_down(nread, curlun->blksize); -+ } -+ file_offset += nread; -+ amount_left -= nread; -+ fsg->residue -= nread; -+ -+ /* Except at the end of the transfer, nread will be -+ * equal to the buffer size, which is divisible by the -+ * bulk-in maxpacket size. -+ */ -+ bh->inreq->length = nread; -+ bh->state = BUF_STATE_FULL; -+ -+ /* If an error occurred, report it and its position */ -+ if (nread < amount) { -+ curlun->sense_data = SS_UNRECOVERED_READ_ERROR; -+ curlun->sense_data_info = file_offset >> curlun->blkbits; -+ curlun->info_valid = 1; -+ break; -+ } -+ -+ if (amount_left == 0) -+ break; // No more left to read -+ -+ /* Send this buffer and go read some more */ -+ bh->inreq->zero = 0; -+ start_transfer(fsg, fsg->bulk_in, bh->inreq, -+ &bh->inreq_busy, &bh->state); -+ fsg->next_buffhd_to_fill = bh->next; -+ } -+ -+ return -EIO; // No default reply -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int do_write(struct fsg_dev *fsg) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ u32 lba; -+ struct fsg_buffhd *bh; -+ int get_some_more; -+ u32 amount_left_to_req, amount_left_to_write; -+ loff_t usb_offset, file_offset, file_offset_tmp; -+ unsigned int amount; -+ ssize_t nwritten; -+ int rc; -+ -+ if (curlun->ro) { -+ curlun->sense_data = SS_WRITE_PROTECTED; -+ return -EINVAL; -+ } -+ spin_lock(&curlun->filp->f_lock); -+ curlun->filp->f_flags &= ~O_SYNC; // Default is not to wait -+ spin_unlock(&curlun->filp->f_lock); -+ -+ /* Get the starting Logical Block Address and check that it's -+ * not too big */ -+ if (fsg->cmnd[0] == WRITE_6) -+ lba = get_unaligned_be24(&fsg->cmnd[1]); -+ else { -+ lba = get_unaligned_be32(&fsg->cmnd[2]); -+ -+ /* We allow DPO (Disable Page Out = don't save data in the -+ * cache) and FUA (Force Unit Access = write directly to the -+ * medium). We don't implement DPO; we implement FUA by -+ * performing synchronous output. */ -+ if ((fsg->cmnd[1] & ~0x18) != 0) { -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ /* FUA */ -+ if (!curlun->nofua && (fsg->cmnd[1] & 0x08)) { -+ spin_lock(&curlun->filp->f_lock); -+ curlun->filp->f_flags |= O_DSYNC; -+ spin_unlock(&curlun->filp->f_lock); -+ } -+ } -+ if (lba >= curlun->num_sectors) { -+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; -+ return -EINVAL; -+ } -+ -+ /* Carry out the file writes */ -+ get_some_more = 1; -+ file_offset = usb_offset = ((loff_t) lba) << curlun->blkbits; -+ amount_left_to_req = amount_left_to_write = fsg->data_size_from_cmnd; -+ -+ while (amount_left_to_write > 0) { -+ -+ /* Queue a request for more data from the host */ -+ bh = fsg->next_buffhd_to_fill; -+ if (bh->state == BUF_STATE_EMPTY && get_some_more) { -+ -+ /* Figure out how much we want to get: -+ * Try to get the remaining amount, -+ * but not more than the buffer size. -+ */ -+ amount = min(amount_left_to_req, mod_data.buflen); -+ -+ /* Beyond the end of the backing file? */ -+ if (usb_offset >= curlun->file_length) { -+ get_some_more = 0; -+ curlun->sense_data = -+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; -+ curlun->sense_data_info = usb_offset >> curlun->blkbits; -+ curlun->info_valid = 1; -+ continue; -+ } -+ -+ /* Get the next buffer */ -+ usb_offset += amount; -+ fsg->usb_amount_left -= amount; -+ amount_left_to_req -= amount; -+ if (amount_left_to_req == 0) -+ get_some_more = 0; -+ -+ /* Except at the end of the transfer, amount will be -+ * equal to the buffer size, which is divisible by -+ * the bulk-out maxpacket size. -+ */ -+ set_bulk_out_req_length(fsg, bh, amount); -+ start_transfer(fsg, fsg->bulk_out, bh->outreq, -+ &bh->outreq_busy, &bh->state); -+ fsg->next_buffhd_to_fill = bh->next; -+ continue; -+ } -+ -+ /* Write the received data to the backing file */ -+ bh = fsg->next_buffhd_to_drain; -+ if (bh->state == BUF_STATE_EMPTY && !get_some_more) -+ break; // We stopped early -+ if (bh->state == BUF_STATE_FULL) { -+ smp_rmb(); -+ fsg->next_buffhd_to_drain = bh->next; -+ bh->state = BUF_STATE_EMPTY; -+ -+ /* Did something go wrong with the transfer? */ -+ if (bh->outreq->status != 0) { -+ curlun->sense_data = SS_COMMUNICATION_FAILURE; -+ curlun->sense_data_info = file_offset >> curlun->blkbits; -+ curlun->info_valid = 1; -+ break; -+ } -+ -+ amount = bh->outreq->actual; -+ if (curlun->file_length - file_offset < amount) { -+ LERROR(curlun, -+ "write %u @ %llu beyond end %llu\n", -+ amount, (unsigned long long) file_offset, -+ (unsigned long long) curlun->file_length); -+ amount = curlun->file_length - file_offset; -+ } -+ -+ /* Don't accept excess data. The spec doesn't say -+ * what to do in this case. We'll ignore the error. -+ */ -+ amount = min(amount, bh->bulk_out_intended_length); -+ -+ /* Don't write a partial block */ -+ amount = round_down(amount, curlun->blksize); -+ if (amount == 0) -+ goto empty_write; -+ -+ /* Perform the write */ -+ file_offset_tmp = file_offset; -+ nwritten = vfs_write(curlun->filp, -+ (char __user *) bh->buf, -+ amount, &file_offset_tmp); -+ VLDBG(curlun, "file write %u @ %llu -> %d\n", amount, -+ (unsigned long long) file_offset, -+ (int) nwritten); -+ if (signal_pending(current)) -+ return -EINTR; // Interrupted! -+ -+ if (nwritten < 0) { -+ LDBG(curlun, "error in file write: %d\n", -+ (int) nwritten); -+ nwritten = 0; -+ } else if (nwritten < amount) { -+ LDBG(curlun, "partial file write: %d/%u\n", -+ (int) nwritten, amount); -+ nwritten = round_down(nwritten, curlun->blksize); -+ } -+ file_offset += nwritten; -+ amount_left_to_write -= nwritten; -+ fsg->residue -= nwritten; -+ -+ /* If an error occurred, report it and its position */ -+ if (nwritten < amount) { -+ curlun->sense_data = SS_WRITE_ERROR; -+ curlun->sense_data_info = file_offset >> curlun->blkbits; -+ curlun->info_valid = 1; -+ break; -+ } -+ -+ empty_write: -+ /* Did the host decide to stop early? */ -+ if (bh->outreq->actual < bh->bulk_out_intended_length) { -+ fsg->short_packet_received = 1; -+ break; -+ } -+ continue; -+ } -+ -+ /* Wait for something to happen */ -+ rc = sleep_thread(fsg); -+ if (rc) -+ return rc; -+ } -+ -+ return -EIO; // No default reply -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int do_synchronize_cache(struct fsg_dev *fsg) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ int rc; -+ -+ /* We ignore the requested LBA and write out all file's -+ * dirty data buffers. */ -+ rc = fsg_lun_fsync_sub(curlun); -+ if (rc) -+ curlun->sense_data = SS_WRITE_ERROR; -+ return 0; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void invalidate_sub(struct fsg_lun *curlun) -+{ -+ struct file *filp = curlun->filp; -+ struct inode *inode = filp->f_path.dentry->d_inode; -+ unsigned long rc; -+ -+ rc = invalidate_mapping_pages(inode->i_mapping, 0, -1); -+ VLDBG(curlun, "invalidate_mapping_pages -> %ld\n", rc); -+} -+ -+static int do_verify(struct fsg_dev *fsg) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ u32 lba; -+ u32 verification_length; -+ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; -+ loff_t file_offset, file_offset_tmp; -+ u32 amount_left; -+ unsigned int amount; -+ ssize_t nread; -+ -+ /* Get the starting Logical Block Address and check that it's -+ * not too big */ -+ lba = get_unaligned_be32(&fsg->cmnd[2]); -+ if (lba >= curlun->num_sectors) { -+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; -+ return -EINVAL; -+ } -+ -+ /* We allow DPO (Disable Page Out = don't save data in the -+ * cache) but we don't implement it. */ -+ if ((fsg->cmnd[1] & ~0x10) != 0) { -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ -+ verification_length = get_unaligned_be16(&fsg->cmnd[7]); -+ if (unlikely(verification_length == 0)) -+ return -EIO; // No default reply -+ -+ /* Prepare to carry out the file verify */ -+ amount_left = verification_length << curlun->blkbits; -+ file_offset = ((loff_t) lba) << curlun->blkbits; -+ -+ /* Write out all the dirty buffers before invalidating them */ -+ fsg_lun_fsync_sub(curlun); -+ if (signal_pending(current)) -+ return -EINTR; -+ -+ invalidate_sub(curlun); -+ if (signal_pending(current)) -+ return -EINTR; -+ -+ /* Just try to read the requested blocks */ -+ while (amount_left > 0) { -+ -+ /* Figure out how much we need to read: -+ * Try to read the remaining amount, but not more than -+ * the buffer size. -+ * And don't try to read past the end of the file. -+ */ -+ amount = min((unsigned int) amount_left, mod_data.buflen); -+ amount = min((loff_t) amount, -+ curlun->file_length - file_offset); -+ if (amount == 0) { -+ curlun->sense_data = -+ SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; -+ curlun->sense_data_info = file_offset >> curlun->blkbits; -+ curlun->info_valid = 1; -+ break; -+ } -+ -+ /* Perform the read */ -+ file_offset_tmp = file_offset; -+ nread = vfs_read(curlun->filp, -+ (char __user *) bh->buf, -+ amount, &file_offset_tmp); -+ VLDBG(curlun, "file read %u @ %llu -> %d\n", amount, -+ (unsigned long long) file_offset, -+ (int) nread); -+ if (signal_pending(current)) -+ return -EINTR; -+ -+ if (nread < 0) { -+ LDBG(curlun, "error in file verify: %d\n", -+ (int) nread); -+ nread = 0; -+ } else if (nread < amount) { -+ LDBG(curlun, "partial file verify: %d/%u\n", -+ (int) nread, amount); -+ nread = round_down(nread, curlun->blksize); -+ } -+ if (nread == 0) { -+ curlun->sense_data = SS_UNRECOVERED_READ_ERROR; -+ curlun->sense_data_info = file_offset >> curlun->blkbits; -+ curlun->info_valid = 1; -+ break; -+ } -+ file_offset += nread; -+ amount_left -= nread; -+ } -+ return 0; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int do_inquiry(struct fsg_dev *fsg, struct fsg_buffhd *bh) -+{ -+ u8 *buf = (u8 *) bh->buf; -+ -+ static char vendor_id[] = "Linux "; -+ static char product_disk_id[] = "File-Stor Gadget"; -+ static char product_cdrom_id[] = "File-CD Gadget "; -+ -+ if (!fsg->curlun) { // Unsupported LUNs are okay -+ fsg->bad_lun_okay = 1; -+ memset(buf, 0, 36); -+ buf[0] = 0x7f; // Unsupported, no device-type -+ buf[4] = 31; // Additional length -+ return 36; -+ } -+ -+ memset(buf, 0, 8); -+ buf[0] = (mod_data.cdrom ? TYPE_ROM : TYPE_DISK); -+ if (mod_data.removable) -+ buf[1] = 0x80; -+ buf[2] = 2; // ANSI SCSI level 2 -+ buf[3] = 2; // SCSI-2 INQUIRY data format -+ buf[4] = 31; // Additional length -+ // No special options -+ sprintf(buf + 8, "%-8s%-16s%04x", vendor_id, -+ (mod_data.cdrom ? product_cdrom_id : -+ product_disk_id), -+ mod_data.release); -+ return 36; -+} -+ -+ -+static int do_request_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ u8 *buf = (u8 *) bh->buf; -+ u32 sd, sdinfo; -+ int valid; -+ -+ /* -+ * From the SCSI-2 spec., section 7.9 (Unit attention condition): -+ * -+ * If a REQUEST SENSE command is received from an initiator -+ * with a pending unit attention condition (before the target -+ * generates the contingent allegiance condition), then the -+ * target shall either: -+ * a) report any pending sense data and preserve the unit -+ * attention condition on the logical unit, or, -+ * b) report the unit attention condition, may discard any -+ * pending sense data, and clear the unit attention -+ * condition on the logical unit for that initiator. -+ * -+ * FSG normally uses option a); enable this code to use option b). -+ */ -+#if 0 -+ if (curlun && curlun->unit_attention_data != SS_NO_SENSE) { -+ curlun->sense_data = curlun->unit_attention_data; -+ curlun->unit_attention_data = SS_NO_SENSE; -+ } -+#endif -+ -+ if (!curlun) { // Unsupported LUNs are okay -+ fsg->bad_lun_okay = 1; -+ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; -+ sdinfo = 0; -+ valid = 0; -+ } else { -+ sd = curlun->sense_data; -+ sdinfo = curlun->sense_data_info; -+ valid = curlun->info_valid << 7; -+ curlun->sense_data = SS_NO_SENSE; -+ curlun->sense_data_info = 0; -+ curlun->info_valid = 0; -+ } -+ -+ memset(buf, 0, 18); -+ buf[0] = valid | 0x70; // Valid, current error -+ buf[2] = SK(sd); -+ put_unaligned_be32(sdinfo, &buf[3]); /* Sense information */ -+ buf[7] = 18 - 8; // Additional sense length -+ buf[12] = ASC(sd); -+ buf[13] = ASCQ(sd); -+ return 18; -+} -+ -+ -+static int do_read_capacity(struct fsg_dev *fsg, struct fsg_buffhd *bh) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ u32 lba = get_unaligned_be32(&fsg->cmnd[2]); -+ int pmi = fsg->cmnd[8]; -+ u8 *buf = (u8 *) bh->buf; -+ -+ /* Check the PMI and LBA fields */ -+ if (pmi > 1 || (pmi == 0 && lba != 0)) { -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ -+ put_unaligned_be32(curlun->num_sectors - 1, &buf[0]); -+ /* Max logical block */ -+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ -+ return 8; -+} -+ -+ -+static int do_read_header(struct fsg_dev *fsg, struct fsg_buffhd *bh) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ int msf = fsg->cmnd[1] & 0x02; -+ u32 lba = get_unaligned_be32(&fsg->cmnd[2]); -+ u8 *buf = (u8 *) bh->buf; -+ -+ if ((fsg->cmnd[1] & ~0x02) != 0) { /* Mask away MSF */ -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ if (lba >= curlun->num_sectors) { -+ curlun->sense_data = SS_LOGICAL_BLOCK_ADDRESS_OUT_OF_RANGE; -+ return -EINVAL; -+ } -+ -+ memset(buf, 0, 8); -+ buf[0] = 0x01; /* 2048 bytes of user data, rest is EC */ -+ store_cdrom_address(&buf[4], msf, lba); -+ return 8; -+} -+ -+ -+static int do_read_toc(struct fsg_dev *fsg, struct fsg_buffhd *bh) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ int msf = fsg->cmnd[1] & 0x02; -+ int start_track = fsg->cmnd[6]; -+ u8 *buf = (u8 *) bh->buf; -+ -+ if ((fsg->cmnd[1] & ~0x02) != 0 || /* Mask away MSF */ -+ start_track > 1) { -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ -+ memset(buf, 0, 20); -+ buf[1] = (20-2); /* TOC data length */ -+ buf[2] = 1; /* First track number */ -+ buf[3] = 1; /* Last track number */ -+ buf[5] = 0x16; /* Data track, copying allowed */ -+ buf[6] = 0x01; /* Only track is number 1 */ -+ store_cdrom_address(&buf[8], msf, 0); -+ -+ buf[13] = 0x16; /* Lead-out track is data */ -+ buf[14] = 0xAA; /* Lead-out track number */ -+ store_cdrom_address(&buf[16], msf, curlun->num_sectors); -+ return 20; -+} -+ -+ -+static int do_mode_sense(struct fsg_dev *fsg, struct fsg_buffhd *bh) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ int mscmnd = fsg->cmnd[0]; -+ u8 *buf = (u8 *) bh->buf; -+ u8 *buf0 = buf; -+ int pc, page_code; -+ int changeable_values, all_pages; -+ int valid_page = 0; -+ int len, limit; -+ -+ if ((fsg->cmnd[1] & ~0x08) != 0) { // Mask away DBD -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ pc = fsg->cmnd[2] >> 6; -+ page_code = fsg->cmnd[2] & 0x3f; -+ if (pc == 3) { -+ curlun->sense_data = SS_SAVING_PARAMETERS_NOT_SUPPORTED; -+ return -EINVAL; -+ } -+ changeable_values = (pc == 1); -+ all_pages = (page_code == 0x3f); -+ -+ /* Write the mode parameter header. Fixed values are: default -+ * medium type, no cache control (DPOFUA), and no block descriptors. -+ * The only variable value is the WriteProtect bit. We will fill in -+ * the mode data length later. */ -+ memset(buf, 0, 8); -+ if (mscmnd == MODE_SENSE) { -+ buf[2] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA -+ buf += 4; -+ limit = 255; -+ } else { // MODE_SENSE_10 -+ buf[3] = (curlun->ro ? 0x80 : 0x00); // WP, DPOFUA -+ buf += 8; -+ limit = 65535; // Should really be mod_data.buflen -+ } -+ -+ /* No block descriptors */ -+ -+ /* The mode pages, in numerical order. The only page we support -+ * is the Caching page. */ -+ if (page_code == 0x08 || all_pages) { -+ valid_page = 1; -+ buf[0] = 0x08; // Page code -+ buf[1] = 10; // Page length -+ memset(buf+2, 0, 10); // None of the fields are changeable -+ -+ if (!changeable_values) { -+ buf[2] = 0x04; // Write cache enable, -+ // Read cache not disabled -+ // No cache retention priorities -+ put_unaligned_be16(0xffff, &buf[4]); -+ /* Don't disable prefetch */ -+ /* Minimum prefetch = 0 */ -+ put_unaligned_be16(0xffff, &buf[8]); -+ /* Maximum prefetch */ -+ put_unaligned_be16(0xffff, &buf[10]); -+ /* Maximum prefetch ceiling */ -+ } -+ buf += 12; -+ } -+ -+ /* Check that a valid page was requested and the mode data length -+ * isn't too long. */ -+ len = buf - buf0; -+ if (!valid_page || len > limit) { -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ -+ /* Store the mode data length */ -+ if (mscmnd == MODE_SENSE) -+ buf0[0] = len - 1; -+ else -+ put_unaligned_be16(len - 2, buf0); -+ return len; -+} -+ -+ -+static int do_start_stop(struct fsg_dev *fsg) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ int loej, start; -+ -+ if (!mod_data.removable) { -+ curlun->sense_data = SS_INVALID_COMMAND; -+ return -EINVAL; -+ } -+ -+ // int immed = fsg->cmnd[1] & 0x01; -+ loej = fsg->cmnd[4] & 0x02; -+ start = fsg->cmnd[4] & 0x01; -+ -+#ifdef CONFIG_USB_FILE_STORAGE_TEST -+ if ((fsg->cmnd[1] & ~0x01) != 0 || // Mask away Immed -+ (fsg->cmnd[4] & ~0x03) != 0) { // Mask LoEj, Start -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ -+ if (!start) { -+ -+ /* Are we allowed to unload the media? */ -+ if (curlun->prevent_medium_removal) { -+ LDBG(curlun, "unload attempt prevented\n"); -+ curlun->sense_data = SS_MEDIUM_REMOVAL_PREVENTED; -+ return -EINVAL; -+ } -+ if (loej) { // Simulate an unload/eject -+ up_read(&fsg->filesem); -+ down_write(&fsg->filesem); -+ fsg_lun_close(curlun); -+ up_write(&fsg->filesem); -+ down_read(&fsg->filesem); -+ } -+ } else { -+ -+ /* Our emulation doesn't support mounting; the medium is -+ * available for use as soon as it is loaded. */ -+ if (!fsg_lun_is_open(curlun)) { -+ curlun->sense_data = SS_MEDIUM_NOT_PRESENT; -+ return -EINVAL; -+ } -+ } -+#endif -+ return 0; -+} -+ -+ -+static int do_prevent_allow(struct fsg_dev *fsg) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ int prevent; -+ -+ if (!mod_data.removable) { -+ curlun->sense_data = SS_INVALID_COMMAND; -+ return -EINVAL; -+ } -+ -+ prevent = fsg->cmnd[4] & 0x01; -+ if ((fsg->cmnd[4] & ~0x01) != 0) { // Mask away Prevent -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ -+ if (curlun->prevent_medium_removal && !prevent) -+ fsg_lun_fsync_sub(curlun); -+ curlun->prevent_medium_removal = prevent; -+ return 0; -+} -+ -+ -+static int do_read_format_capacities(struct fsg_dev *fsg, -+ struct fsg_buffhd *bh) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ u8 *buf = (u8 *) bh->buf; -+ -+ buf[0] = buf[1] = buf[2] = 0; -+ buf[3] = 8; // Only the Current/Maximum Capacity Descriptor -+ buf += 4; -+ -+ put_unaligned_be32(curlun->num_sectors, &buf[0]); -+ /* Number of blocks */ -+ put_unaligned_be32(curlun->blksize, &buf[4]); /* Block length */ -+ buf[4] = 0x02; /* Current capacity */ -+ return 12; -+} -+ -+ -+static int do_mode_select(struct fsg_dev *fsg, struct fsg_buffhd *bh) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ -+ /* We don't support MODE SELECT */ -+ curlun->sense_data = SS_INVALID_COMMAND; -+ return -EINVAL; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int halt_bulk_in_endpoint(struct fsg_dev *fsg) -+{ -+ int rc; -+ -+ rc = fsg_set_halt(fsg, fsg->bulk_in); -+ if (rc == -EAGAIN) -+ VDBG(fsg, "delayed bulk-in endpoint halt\n"); -+ while (rc != 0) { -+ if (rc != -EAGAIN) { -+ WARNING(fsg, "usb_ep_set_halt -> %d\n", rc); -+ rc = 0; -+ break; -+ } -+ -+ /* Wait for a short time and then try again */ -+ if (msleep_interruptible(100) != 0) -+ return -EINTR; -+ rc = usb_ep_set_halt(fsg->bulk_in); -+ } -+ return rc; -+} -+ -+static int wedge_bulk_in_endpoint(struct fsg_dev *fsg) -+{ -+ int rc; -+ -+ DBG(fsg, "bulk-in set wedge\n"); -+ rc = usb_ep_set_wedge(fsg->bulk_in); -+ if (rc == -EAGAIN) -+ VDBG(fsg, "delayed bulk-in endpoint wedge\n"); -+ while (rc != 0) { -+ if (rc != -EAGAIN) { -+ WARNING(fsg, "usb_ep_set_wedge -> %d\n", rc); -+ rc = 0; -+ break; -+ } -+ -+ /* Wait for a short time and then try again */ -+ if (msleep_interruptible(100) != 0) -+ return -EINTR; -+ rc = usb_ep_set_wedge(fsg->bulk_in); -+ } -+ return rc; -+} -+ -+static int throw_away_data(struct fsg_dev *fsg) -+{ -+ struct fsg_buffhd *bh; -+ u32 amount; -+ int rc; -+ -+ while ((bh = fsg->next_buffhd_to_drain)->state != BUF_STATE_EMPTY || -+ fsg->usb_amount_left > 0) { -+ -+ /* Throw away the data in a filled buffer */ -+ if (bh->state == BUF_STATE_FULL) { -+ smp_rmb(); -+ bh->state = BUF_STATE_EMPTY; -+ fsg->next_buffhd_to_drain = bh->next; -+ -+ /* A short packet or an error ends everything */ -+ if (bh->outreq->actual < bh->bulk_out_intended_length || -+ bh->outreq->status != 0) { -+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); -+ return -EINTR; -+ } -+ continue; -+ } -+ -+ /* Try to submit another request if we need one */ -+ bh = fsg->next_buffhd_to_fill; -+ if (bh->state == BUF_STATE_EMPTY && fsg->usb_amount_left > 0) { -+ amount = min(fsg->usb_amount_left, -+ (u32) mod_data.buflen); -+ -+ /* Except at the end of the transfer, amount will be -+ * equal to the buffer size, which is divisible by -+ * the bulk-out maxpacket size. -+ */ -+ set_bulk_out_req_length(fsg, bh, amount); -+ start_transfer(fsg, fsg->bulk_out, bh->outreq, -+ &bh->outreq_busy, &bh->state); -+ fsg->next_buffhd_to_fill = bh->next; -+ fsg->usb_amount_left -= amount; -+ continue; -+ } -+ -+ /* Otherwise wait for something to happen */ -+ rc = sleep_thread(fsg); -+ if (rc) -+ return rc; -+ } -+ return 0; -+} -+ -+ -+static int finish_reply(struct fsg_dev *fsg) -+{ -+ struct fsg_buffhd *bh = fsg->next_buffhd_to_fill; -+ int rc = 0; -+ -+ switch (fsg->data_dir) { -+ case DATA_DIR_NONE: -+ break; // Nothing to send -+ -+ /* If we don't know whether the host wants to read or write, -+ * this must be CB or CBI with an unknown command. We mustn't -+ * try to send or receive any data. So stall both bulk pipes -+ * if we can and wait for a reset. */ -+ case DATA_DIR_UNKNOWN: -+ if (mod_data.can_stall) { -+ fsg_set_halt(fsg, fsg->bulk_out); -+ rc = halt_bulk_in_endpoint(fsg); -+ } -+ break; -+ -+ /* All but the last buffer of data must have already been sent */ -+ case DATA_DIR_TO_HOST: -+ if (fsg->data_size == 0) -+ ; // Nothing to send -+ -+ /* If there's no residue, simply send the last buffer */ -+ else if (fsg->residue == 0) { -+ bh->inreq->zero = 0; -+ start_transfer(fsg, fsg->bulk_in, bh->inreq, -+ &bh->inreq_busy, &bh->state); -+ fsg->next_buffhd_to_fill = bh->next; -+ } -+ -+ /* There is a residue. For CB and CBI, simply mark the end -+ * of the data with a short packet. However, if we are -+ * allowed to stall, there was no data at all (residue == -+ * data_size), and the command failed (invalid LUN or -+ * sense data is set), then halt the bulk-in endpoint -+ * instead. */ -+ else if (!transport_is_bbb()) { -+ if (mod_data.can_stall && -+ fsg->residue == fsg->data_size && -+ (!fsg->curlun || fsg->curlun->sense_data != SS_NO_SENSE)) { -+ bh->state = BUF_STATE_EMPTY; -+ rc = halt_bulk_in_endpoint(fsg); -+ } else { -+ bh->inreq->zero = 1; -+ start_transfer(fsg, fsg->bulk_in, bh->inreq, -+ &bh->inreq_busy, &bh->state); -+ fsg->next_buffhd_to_fill = bh->next; -+ } -+ } -+ -+ /* -+ * For Bulk-only, mark the end of the data with a short -+ * packet. If we are allowed to stall, halt the bulk-in -+ * endpoint. (Note: This violates the Bulk-Only Transport -+ * specification, which requires us to pad the data if we -+ * don't halt the endpoint. Presumably nobody will mind.) -+ */ -+ else { -+ bh->inreq->zero = 1; -+ start_transfer(fsg, fsg->bulk_in, bh->inreq, -+ &bh->inreq_busy, &bh->state); -+ fsg->next_buffhd_to_fill = bh->next; -+ if (mod_data.can_stall) -+ rc = halt_bulk_in_endpoint(fsg); -+ } -+ break; -+ -+ /* We have processed all we want from the data the host has sent. -+ * There may still be outstanding bulk-out requests. */ -+ case DATA_DIR_FROM_HOST: -+ if (fsg->residue == 0) -+ ; // Nothing to receive -+ -+ /* Did the host stop sending unexpectedly early? */ -+ else if (fsg->short_packet_received) { -+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); -+ rc = -EINTR; -+ } -+ -+ /* We haven't processed all the incoming data. Even though -+ * we may be allowed to stall, doing so would cause a race. -+ * The controller may already have ACK'ed all the remaining -+ * bulk-out packets, in which case the host wouldn't see a -+ * STALL. Not realizing the endpoint was halted, it wouldn't -+ * clear the halt -- leading to problems later on. */ -+#if 0 -+ else if (mod_data.can_stall) { -+ fsg_set_halt(fsg, fsg->bulk_out); -+ raise_exception(fsg, FSG_STATE_ABORT_BULK_OUT); -+ rc = -EINTR; -+ } -+#endif -+ -+ /* We can't stall. Read in the excess data and throw it -+ * all away. */ -+ else -+ rc = throw_away_data(fsg); -+ break; -+ } -+ return rc; -+} -+ -+ -+static int send_status(struct fsg_dev *fsg) -+{ -+ struct fsg_lun *curlun = fsg->curlun; -+ struct fsg_buffhd *bh; -+ int rc; -+ u8 status = US_BULK_STAT_OK; -+ u32 sd, sdinfo = 0; -+ -+ /* Wait for the next buffer to become available */ -+ bh = fsg->next_buffhd_to_fill; -+ while (bh->state != BUF_STATE_EMPTY) { -+ rc = sleep_thread(fsg); -+ if (rc) -+ return rc; -+ } -+ -+ if (curlun) { -+ sd = curlun->sense_data; -+ sdinfo = curlun->sense_data_info; -+ } else if (fsg->bad_lun_okay) -+ sd = SS_NO_SENSE; -+ else -+ sd = SS_LOGICAL_UNIT_NOT_SUPPORTED; -+ -+ if (fsg->phase_error) { -+ DBG(fsg, "sending phase-error status\n"); -+ status = US_BULK_STAT_PHASE; -+ sd = SS_INVALID_COMMAND; -+ } else if (sd != SS_NO_SENSE) { -+ DBG(fsg, "sending command-failure status\n"); -+ status = US_BULK_STAT_FAIL; -+ VDBG(fsg, " sense data: SK x%02x, ASC x%02x, ASCQ x%02x;" -+ " info x%x\n", -+ SK(sd), ASC(sd), ASCQ(sd), sdinfo); -+ } -+ -+ if (transport_is_bbb()) { -+ struct bulk_cs_wrap *csw = bh->buf; -+ -+ /* Store and send the Bulk-only CSW */ -+ csw->Signature = cpu_to_le32(US_BULK_CS_SIGN); -+ csw->Tag = fsg->tag; -+ csw->Residue = cpu_to_le32(fsg->residue); -+ csw->Status = status; -+ -+ bh->inreq->length = US_BULK_CS_WRAP_LEN; -+ bh->inreq->zero = 0; -+ start_transfer(fsg, fsg->bulk_in, bh->inreq, -+ &bh->inreq_busy, &bh->state); -+ -+ } else if (mod_data.transport_type == USB_PR_CB) { -+ -+ /* Control-Bulk transport has no status phase! */ -+ return 0; -+ -+ } else { // USB_PR_CBI -+ struct interrupt_data *buf = bh->buf; -+ -+ /* Store and send the Interrupt data. UFI sends the ASC -+ * and ASCQ bytes. Everything else sends a Type (which -+ * is always 0) and the status Value. */ -+ if (mod_data.protocol_type == USB_SC_UFI) { -+ buf->bType = ASC(sd); -+ buf->bValue = ASCQ(sd); -+ } else { -+ buf->bType = 0; -+ buf->bValue = status; -+ } -+ fsg->intreq->length = CBI_INTERRUPT_DATA_LEN; -+ -+ fsg->intr_buffhd = bh; // Point to the right buffhd -+ fsg->intreq->buf = bh->inreq->buf; -+ fsg->intreq->context = bh; -+ start_transfer(fsg, fsg->intr_in, fsg->intreq, -+ &fsg->intreq_busy, &bh->state); -+ } -+ -+ fsg->next_buffhd_to_fill = bh->next; -+ return 0; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+/* Check whether the command is properly formed and whether its data size -+ * and direction agree with the values we already have. */ -+static int check_command(struct fsg_dev *fsg, int cmnd_size, -+ enum data_direction data_dir, unsigned int mask, -+ int needs_medium, const char *name) -+{ -+ int i; -+ int lun = fsg->cmnd[1] >> 5; -+ static const char dirletter[4] = {'u', 'o', 'i', 'n'}; -+ char hdlen[20]; -+ struct fsg_lun *curlun; -+ -+ /* Adjust the expected cmnd_size for protocol encapsulation padding. -+ * Transparent SCSI doesn't pad. */ -+ if (protocol_is_scsi()) -+ ; -+ -+ /* There's some disagreement as to whether RBC pads commands or not. -+ * We'll play it safe and accept either form. */ -+ else if (mod_data.protocol_type == USB_SC_RBC) { -+ if (fsg->cmnd_size == 12) -+ cmnd_size = 12; -+ -+ /* All the other protocols pad to 12 bytes */ -+ } else -+ cmnd_size = 12; -+ -+ hdlen[0] = 0; -+ if (fsg->data_dir != DATA_DIR_UNKNOWN) -+ sprintf(hdlen, ", H%c=%u", dirletter[(int) fsg->data_dir], -+ fsg->data_size); -+ VDBG(fsg, "SCSI command: %s; Dc=%d, D%c=%u; Hc=%d%s\n", -+ name, cmnd_size, dirletter[(int) data_dir], -+ fsg->data_size_from_cmnd, fsg->cmnd_size, hdlen); -+ -+ /* We can't reply at all until we know the correct data direction -+ * and size. */ -+ if (fsg->data_size_from_cmnd == 0) -+ data_dir = DATA_DIR_NONE; -+ if (fsg->data_dir == DATA_DIR_UNKNOWN) { // CB or CBI -+ fsg->data_dir = data_dir; -+ fsg->data_size = fsg->data_size_from_cmnd; -+ -+ } else { // Bulk-only -+ if (fsg->data_size < fsg->data_size_from_cmnd) { -+ -+ /* Host data size < Device data size is a phase error. -+ * Carry out the command, but only transfer as much -+ * as we are allowed. */ -+ fsg->data_size_from_cmnd = fsg->data_size; -+ fsg->phase_error = 1; -+ } -+ } -+ fsg->residue = fsg->usb_amount_left = fsg->data_size; -+ -+ /* Conflicting data directions is a phase error */ -+ if (fsg->data_dir != data_dir && fsg->data_size_from_cmnd > 0) { -+ fsg->phase_error = 1; -+ return -EINVAL; -+ } -+ -+ /* Verify the length of the command itself */ -+ if (cmnd_size != fsg->cmnd_size) { -+ -+ /* Special case workaround: There are plenty of buggy SCSI -+ * implementations. Many have issues with cbw->Length -+ * field passing a wrong command size. For those cases we -+ * always try to work around the problem by using the length -+ * sent by the host side provided it is at least as large -+ * as the correct command length. -+ * Examples of such cases would be MS-Windows, which issues -+ * REQUEST SENSE with cbw->Length == 12 where it should -+ * be 6, and xbox360 issuing INQUIRY, TEST UNIT READY and -+ * REQUEST SENSE with cbw->Length == 10 where it should -+ * be 6 as well. -+ */ -+ if (cmnd_size <= fsg->cmnd_size) { -+ DBG(fsg, "%s is buggy! Expected length %d " -+ "but we got %d\n", name, -+ cmnd_size, fsg->cmnd_size); -+ cmnd_size = fsg->cmnd_size; -+ } else { -+ fsg->phase_error = 1; -+ return -EINVAL; -+ } -+ } -+ -+ /* Check that the LUN values are consistent */ -+ if (transport_is_bbb()) { -+ if (fsg->lun != lun) -+ DBG(fsg, "using LUN %d from CBW, " -+ "not LUN %d from CDB\n", -+ fsg->lun, lun); -+ } -+ -+ /* Check the LUN */ -+ curlun = fsg->curlun; -+ if (curlun) { -+ if (fsg->cmnd[0] != REQUEST_SENSE) { -+ curlun->sense_data = SS_NO_SENSE; -+ curlun->sense_data_info = 0; -+ curlun->info_valid = 0; -+ } -+ } else { -+ fsg->bad_lun_okay = 0; -+ -+ /* INQUIRY and REQUEST SENSE commands are explicitly allowed -+ * to use unsupported LUNs; all others may not. */ -+ if (fsg->cmnd[0] != INQUIRY && -+ fsg->cmnd[0] != REQUEST_SENSE) { -+ DBG(fsg, "unsupported LUN %d\n", fsg->lun); -+ return -EINVAL; -+ } -+ } -+ -+ /* If a unit attention condition exists, only INQUIRY and -+ * REQUEST SENSE commands are allowed; anything else must fail. */ -+ if (curlun && curlun->unit_attention_data != SS_NO_SENSE && -+ fsg->cmnd[0] != INQUIRY && -+ fsg->cmnd[0] != REQUEST_SENSE) { -+ curlun->sense_data = curlun->unit_attention_data; -+ curlun->unit_attention_data = SS_NO_SENSE; -+ return -EINVAL; -+ } -+ -+ /* Check that only command bytes listed in the mask are non-zero */ -+ fsg->cmnd[1] &= 0x1f; // Mask away the LUN -+ for (i = 1; i < cmnd_size; ++i) { -+ if (fsg->cmnd[i] && !(mask & (1 << i))) { -+ if (curlun) -+ curlun->sense_data = SS_INVALID_FIELD_IN_CDB; -+ return -EINVAL; -+ } -+ } -+ -+ /* If the medium isn't mounted and the command needs to access -+ * it, return an error. */ -+ if (curlun && !fsg_lun_is_open(curlun) && needs_medium) { -+ curlun->sense_data = SS_MEDIUM_NOT_PRESENT; -+ return -EINVAL; -+ } -+ -+ return 0; -+} -+ -+/* wrapper of check_command for data size in blocks handling */ -+static int check_command_size_in_blocks(struct fsg_dev *fsg, int cmnd_size, -+ enum data_direction data_dir, unsigned int mask, -+ int needs_medium, const char *name) -+{ -+ if (fsg->curlun) -+ fsg->data_size_from_cmnd <<= fsg->curlun->blkbits; -+ return check_command(fsg, cmnd_size, data_dir, -+ mask, needs_medium, name); -+} -+ -+static int do_scsi_command(struct fsg_dev *fsg) -+{ -+ struct fsg_buffhd *bh; -+ int rc; -+ int reply = -EINVAL; -+ int i; -+ static char unknown[16]; -+ -+ dump_cdb(fsg); -+ -+ /* Wait for the next buffer to become available for data or status */ -+ bh = fsg->next_buffhd_to_drain = fsg->next_buffhd_to_fill; -+ while (bh->state != BUF_STATE_EMPTY) { -+ rc = sleep_thread(fsg); -+ if (rc) -+ return rc; -+ } -+ fsg->phase_error = 0; -+ fsg->short_packet_received = 0; -+ -+ down_read(&fsg->filesem); // We're using the backing file -+ switch (fsg->cmnd[0]) { -+ -+ case INQUIRY: -+ fsg->data_size_from_cmnd = fsg->cmnd[4]; -+ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, -+ (1<<4), 0, -+ "INQUIRY")) == 0) -+ reply = do_inquiry(fsg, bh); -+ break; -+ -+ case MODE_SELECT: -+ fsg->data_size_from_cmnd = fsg->cmnd[4]; -+ if ((reply = check_command(fsg, 6, DATA_DIR_FROM_HOST, -+ (1<<1) | (1<<4), 0, -+ "MODE SELECT(6)")) == 0) -+ reply = do_mode_select(fsg, bh); -+ break; -+ -+ case MODE_SELECT_10: -+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); -+ if ((reply = check_command(fsg, 10, DATA_DIR_FROM_HOST, -+ (1<<1) | (3<<7), 0, -+ "MODE SELECT(10)")) == 0) -+ reply = do_mode_select(fsg, bh); -+ break; -+ -+ case MODE_SENSE: -+ fsg->data_size_from_cmnd = fsg->cmnd[4]; -+ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, -+ (1<<1) | (1<<2) | (1<<4), 0, -+ "MODE SENSE(6)")) == 0) -+ reply = do_mode_sense(fsg, bh); -+ break; -+ -+ case MODE_SENSE_10: -+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); -+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, -+ (1<<1) | (1<<2) | (3<<7), 0, -+ "MODE SENSE(10)")) == 0) -+ reply = do_mode_sense(fsg, bh); -+ break; -+ -+ case ALLOW_MEDIUM_REMOVAL: -+ fsg->data_size_from_cmnd = 0; -+ if ((reply = check_command(fsg, 6, DATA_DIR_NONE, -+ (1<<4), 0, -+ "PREVENT-ALLOW MEDIUM REMOVAL")) == 0) -+ reply = do_prevent_allow(fsg); -+ break; -+ -+ case READ_6: -+ i = fsg->cmnd[4]; -+ fsg->data_size_from_cmnd = (i == 0) ? 256 : i; -+ if ((reply = check_command_size_in_blocks(fsg, 6, -+ DATA_DIR_TO_HOST, -+ (7<<1) | (1<<4), 1, -+ "READ(6)")) == 0) -+ reply = do_read(fsg); -+ break; -+ -+ case READ_10: -+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); -+ if ((reply = check_command_size_in_blocks(fsg, 10, -+ DATA_DIR_TO_HOST, -+ (1<<1) | (0xf<<2) | (3<<7), 1, -+ "READ(10)")) == 0) -+ reply = do_read(fsg); -+ break; -+ -+ case READ_12: -+ fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); -+ if ((reply = check_command_size_in_blocks(fsg, 12, -+ DATA_DIR_TO_HOST, -+ (1<<1) | (0xf<<2) | (0xf<<6), 1, -+ "READ(12)")) == 0) -+ reply = do_read(fsg); -+ break; -+ -+ case READ_CAPACITY: -+ fsg->data_size_from_cmnd = 8; -+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, -+ (0xf<<2) | (1<<8), 1, -+ "READ CAPACITY")) == 0) -+ reply = do_read_capacity(fsg, bh); -+ break; -+ -+ case READ_HEADER: -+ if (!mod_data.cdrom) -+ goto unknown_cmnd; -+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); -+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, -+ (3<<7) | (0x1f<<1), 1, -+ "READ HEADER")) == 0) -+ reply = do_read_header(fsg, bh); -+ break; -+ -+ case READ_TOC: -+ if (!mod_data.cdrom) -+ goto unknown_cmnd; -+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); -+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, -+ (7<<6) | (1<<1), 1, -+ "READ TOC")) == 0) -+ reply = do_read_toc(fsg, bh); -+ break; -+ -+ case READ_FORMAT_CAPACITIES: -+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); -+ if ((reply = check_command(fsg, 10, DATA_DIR_TO_HOST, -+ (3<<7), 1, -+ "READ FORMAT CAPACITIES")) == 0) -+ reply = do_read_format_capacities(fsg, bh); -+ break; -+ -+ case REQUEST_SENSE: -+ fsg->data_size_from_cmnd = fsg->cmnd[4]; -+ if ((reply = check_command(fsg, 6, DATA_DIR_TO_HOST, -+ (1<<4), 0, -+ "REQUEST SENSE")) == 0) -+ reply = do_request_sense(fsg, bh); -+ break; -+ -+ case START_STOP: -+ fsg->data_size_from_cmnd = 0; -+ if ((reply = check_command(fsg, 6, DATA_DIR_NONE, -+ (1<<1) | (1<<4), 0, -+ "START-STOP UNIT")) == 0) -+ reply = do_start_stop(fsg); -+ break; -+ -+ case SYNCHRONIZE_CACHE: -+ fsg->data_size_from_cmnd = 0; -+ if ((reply = check_command(fsg, 10, DATA_DIR_NONE, -+ (0xf<<2) | (3<<7), 1, -+ "SYNCHRONIZE CACHE")) == 0) -+ reply = do_synchronize_cache(fsg); -+ break; -+ -+ case TEST_UNIT_READY: -+ fsg->data_size_from_cmnd = 0; -+ reply = check_command(fsg, 6, DATA_DIR_NONE, -+ 0, 1, -+ "TEST UNIT READY"); -+ break; -+ -+ /* Although optional, this command is used by MS-Windows. We -+ * support a minimal version: BytChk must be 0. */ -+ case VERIFY: -+ fsg->data_size_from_cmnd = 0; -+ if ((reply = check_command(fsg, 10, DATA_DIR_NONE, -+ (1<<1) | (0xf<<2) | (3<<7), 1, -+ "VERIFY")) == 0) -+ reply = do_verify(fsg); -+ break; -+ -+ case WRITE_6: -+ i = fsg->cmnd[4]; -+ fsg->data_size_from_cmnd = (i == 0) ? 256 : i; -+ if ((reply = check_command_size_in_blocks(fsg, 6, -+ DATA_DIR_FROM_HOST, -+ (7<<1) | (1<<4), 1, -+ "WRITE(6)")) == 0) -+ reply = do_write(fsg); -+ break; -+ -+ case WRITE_10: -+ fsg->data_size_from_cmnd = get_unaligned_be16(&fsg->cmnd[7]); -+ if ((reply = check_command_size_in_blocks(fsg, 10, -+ DATA_DIR_FROM_HOST, -+ (1<<1) | (0xf<<2) | (3<<7), 1, -+ "WRITE(10)")) == 0) -+ reply = do_write(fsg); -+ break; -+ -+ case WRITE_12: -+ fsg->data_size_from_cmnd = get_unaligned_be32(&fsg->cmnd[6]); -+ if ((reply = check_command_size_in_blocks(fsg, 12, -+ DATA_DIR_FROM_HOST, -+ (1<<1) | (0xf<<2) | (0xf<<6), 1, -+ "WRITE(12)")) == 0) -+ reply = do_write(fsg); -+ break; -+ -+ /* Some mandatory commands that we recognize but don't implement. -+ * They don't mean much in this setting. It's left as an exercise -+ * for anyone interested to implement RESERVE and RELEASE in terms -+ * of Posix locks. */ -+ case FORMAT_UNIT: -+ case RELEASE: -+ case RESERVE: -+ case SEND_DIAGNOSTIC: -+ // Fall through -+ -+ default: -+ unknown_cmnd: -+ fsg->data_size_from_cmnd = 0; -+ sprintf(unknown, "Unknown x%02x", fsg->cmnd[0]); -+ if ((reply = check_command(fsg, fsg->cmnd_size, -+ DATA_DIR_UNKNOWN, ~0, 0, unknown)) == 0) { -+ fsg->curlun->sense_data = SS_INVALID_COMMAND; -+ reply = -EINVAL; -+ } -+ break; -+ } -+ up_read(&fsg->filesem); -+ -+ if (reply == -EINTR || signal_pending(current)) -+ return -EINTR; -+ -+ /* Set up the single reply buffer for finish_reply() */ -+ if (reply == -EINVAL) -+ reply = 0; // Error reply length -+ if (reply >= 0 && fsg->data_dir == DATA_DIR_TO_HOST) { -+ reply = min((u32) reply, fsg->data_size_from_cmnd); -+ bh->inreq->length = reply; -+ bh->state = BUF_STATE_FULL; -+ fsg->residue -= reply; -+ } // Otherwise it's already set -+ -+ return 0; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int received_cbw(struct fsg_dev *fsg, struct fsg_buffhd *bh) -+{ -+ struct usb_request *req = bh->outreq; -+ struct bulk_cb_wrap *cbw = req->buf; -+ -+ /* Was this a real packet? Should it be ignored? */ -+ if (req->status || test_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) -+ return -EINVAL; -+ -+ /* Is the CBW valid? */ -+ if (req->actual != US_BULK_CB_WRAP_LEN || -+ cbw->Signature != cpu_to_le32( -+ US_BULK_CB_SIGN)) { -+ DBG(fsg, "invalid CBW: len %u sig 0x%x\n", -+ req->actual, -+ le32_to_cpu(cbw->Signature)); -+ -+ /* The Bulk-only spec says we MUST stall the IN endpoint -+ * (6.6.1), so it's unavoidable. It also says we must -+ * retain this state until the next reset, but there's -+ * no way to tell the controller driver it should ignore -+ * Clear-Feature(HALT) requests. -+ * -+ * We aren't required to halt the OUT endpoint; instead -+ * we can simply accept and discard any data received -+ * until the next reset. */ -+ wedge_bulk_in_endpoint(fsg); -+ set_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); -+ return -EINVAL; -+ } -+ -+ /* Is the CBW meaningful? */ -+ if (cbw->Lun >= FSG_MAX_LUNS || cbw->Flags & ~US_BULK_FLAG_IN || -+ cbw->Length <= 0 || cbw->Length > MAX_COMMAND_SIZE) { -+ DBG(fsg, "non-meaningful CBW: lun = %u, flags = 0x%x, " -+ "cmdlen %u\n", -+ cbw->Lun, cbw->Flags, cbw->Length); -+ -+ /* We can do anything we want here, so let's stall the -+ * bulk pipes if we are allowed to. */ -+ if (mod_data.can_stall) { -+ fsg_set_halt(fsg, fsg->bulk_out); -+ halt_bulk_in_endpoint(fsg); -+ } -+ return -EINVAL; -+ } -+ -+ /* Save the command for later */ -+ fsg->cmnd_size = cbw->Length; -+ memcpy(fsg->cmnd, cbw->CDB, fsg->cmnd_size); -+ if (cbw->Flags & US_BULK_FLAG_IN) -+ fsg->data_dir = DATA_DIR_TO_HOST; -+ else -+ fsg->data_dir = DATA_DIR_FROM_HOST; -+ fsg->data_size = le32_to_cpu(cbw->DataTransferLength); -+ if (fsg->data_size == 0) -+ fsg->data_dir = DATA_DIR_NONE; -+ fsg->lun = cbw->Lun; -+ fsg->tag = cbw->Tag; -+ return 0; -+} -+ -+ -+static int get_next_command(struct fsg_dev *fsg) -+{ -+ struct fsg_buffhd *bh; -+ int rc = 0; -+ -+ if (transport_is_bbb()) { -+ -+ /* Wait for the next buffer to become available */ -+ bh = fsg->next_buffhd_to_fill; -+ while (bh->state != BUF_STATE_EMPTY) { -+ rc = sleep_thread(fsg); -+ if (rc) -+ return rc; -+ } -+ -+ /* Queue a request to read a Bulk-only CBW */ -+ set_bulk_out_req_length(fsg, bh, US_BULK_CB_WRAP_LEN); -+ start_transfer(fsg, fsg->bulk_out, bh->outreq, -+ &bh->outreq_busy, &bh->state); -+ -+ /* We will drain the buffer in software, which means we -+ * can reuse it for the next filling. No need to advance -+ * next_buffhd_to_fill. */ -+ -+ /* Wait for the CBW to arrive */ -+ while (bh->state != BUF_STATE_FULL) { -+ rc = sleep_thread(fsg); -+ if (rc) -+ return rc; -+ } -+ smp_rmb(); -+ rc = received_cbw(fsg, bh); -+ bh->state = BUF_STATE_EMPTY; -+ -+ } else { // USB_PR_CB or USB_PR_CBI -+ -+ /* Wait for the next command to arrive */ -+ while (fsg->cbbuf_cmnd_size == 0) { -+ rc = sleep_thread(fsg); -+ if (rc) -+ return rc; -+ } -+ -+ /* Is the previous status interrupt request still busy? -+ * The host is allowed to skip reading the status, -+ * so we must cancel it. */ -+ if (fsg->intreq_busy) -+ usb_ep_dequeue(fsg->intr_in, fsg->intreq); -+ -+ /* Copy the command and mark the buffer empty */ -+ fsg->data_dir = DATA_DIR_UNKNOWN; -+ spin_lock_irq(&fsg->lock); -+ fsg->cmnd_size = fsg->cbbuf_cmnd_size; -+ memcpy(fsg->cmnd, fsg->cbbuf_cmnd, fsg->cmnd_size); -+ fsg->cbbuf_cmnd_size = 0; -+ spin_unlock_irq(&fsg->lock); -+ -+ /* Use LUN from the command */ -+ fsg->lun = fsg->cmnd[1] >> 5; -+ } -+ -+ /* Update current lun */ -+ if (fsg->lun >= 0 && fsg->lun < fsg->nluns) -+ fsg->curlun = &fsg->luns[fsg->lun]; -+ else -+ fsg->curlun = NULL; -+ -+ return rc; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int enable_endpoint(struct fsg_dev *fsg, struct usb_ep *ep, -+ const struct usb_endpoint_descriptor *d) -+{ -+ int rc; -+ -+ ep->driver_data = fsg; -+ ep->desc = d; -+ rc = usb_ep_enable(ep); -+ if (rc) -+ ERROR(fsg, "can't enable %s, result %d\n", ep->name, rc); -+ return rc; -+} -+ -+static int alloc_request(struct fsg_dev *fsg, struct usb_ep *ep, -+ struct usb_request **preq) -+{ -+ *preq = usb_ep_alloc_request(ep, GFP_ATOMIC); -+ if (*preq) -+ return 0; -+ ERROR(fsg, "can't allocate request for %s\n", ep->name); -+ return -ENOMEM; -+} -+ -+/* -+ * Reset interface setting and re-init endpoint state (toggle etc). -+ * Call with altsetting < 0 to disable the interface. The only other -+ * available altsetting is 0, which enables the interface. -+ */ -+static int do_set_interface(struct fsg_dev *fsg, int altsetting) -+{ -+ int rc = 0; -+ int i; -+ const struct usb_endpoint_descriptor *d; -+ -+ if (fsg->running) -+ DBG(fsg, "reset interface\n"); -+ -+reset: -+ /* Deallocate the requests */ -+ for (i = 0; i < fsg_num_buffers; ++i) { -+ struct fsg_buffhd *bh = &fsg->buffhds[i]; -+ -+ if (bh->inreq) { -+ usb_ep_free_request(fsg->bulk_in, bh->inreq); -+ bh->inreq = NULL; -+ } -+ if (bh->outreq) { -+ usb_ep_free_request(fsg->bulk_out, bh->outreq); -+ bh->outreq = NULL; -+ } -+ } -+ if (fsg->intreq) { -+ usb_ep_free_request(fsg->intr_in, fsg->intreq); -+ fsg->intreq = NULL; -+ } -+ -+ /* Disable the endpoints */ -+ if (fsg->bulk_in_enabled) { -+ usb_ep_disable(fsg->bulk_in); -+ fsg->bulk_in_enabled = 0; -+ } -+ if (fsg->bulk_out_enabled) { -+ usb_ep_disable(fsg->bulk_out); -+ fsg->bulk_out_enabled = 0; -+ } -+ if (fsg->intr_in_enabled) { -+ usb_ep_disable(fsg->intr_in); -+ fsg->intr_in_enabled = 0; -+ } -+ -+ fsg->running = 0; -+ if (altsetting < 0 || rc != 0) -+ return rc; -+ -+ DBG(fsg, "set interface %d\n", altsetting); -+ -+ /* Enable the endpoints */ -+ d = fsg_ep_desc(fsg->gadget, -+ &fsg_fs_bulk_in_desc, &fsg_hs_bulk_in_desc, -+ &fsg_ss_bulk_in_desc); -+ if ((rc = enable_endpoint(fsg, fsg->bulk_in, d)) != 0) -+ goto reset; -+ fsg->bulk_in_enabled = 1; -+ -+ d = fsg_ep_desc(fsg->gadget, -+ &fsg_fs_bulk_out_desc, &fsg_hs_bulk_out_desc, -+ &fsg_ss_bulk_out_desc); -+ if ((rc = enable_endpoint(fsg, fsg->bulk_out, d)) != 0) -+ goto reset; -+ fsg->bulk_out_enabled = 1; -+ fsg->bulk_out_maxpacket = usb_endpoint_maxp(d); -+ clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags); -+ -+ if (transport_is_cbi()) { -+ d = fsg_ep_desc(fsg->gadget, -+ &fsg_fs_intr_in_desc, &fsg_hs_intr_in_desc, -+ &fsg_ss_intr_in_desc); -+ if ((rc = enable_endpoint(fsg, fsg->intr_in, d)) != 0) -+ goto reset; -+ fsg->intr_in_enabled = 1; -+ } -+ -+ /* Allocate the requests */ -+ for (i = 0; i < fsg_num_buffers; ++i) { -+ struct fsg_buffhd *bh = &fsg->buffhds[i]; -+ -+ if ((rc = alloc_request(fsg, fsg->bulk_in, &bh->inreq)) != 0) -+ goto reset; -+ if ((rc = alloc_request(fsg, fsg->bulk_out, &bh->outreq)) != 0) -+ goto reset; -+ bh->inreq->buf = bh->outreq->buf = bh->buf; -+ bh->inreq->context = bh->outreq->context = bh; -+ bh->inreq->complete = bulk_in_complete; -+ bh->outreq->complete = bulk_out_complete; -+ } -+ if (transport_is_cbi()) { -+ if ((rc = alloc_request(fsg, fsg->intr_in, &fsg->intreq)) != 0) -+ goto reset; -+ fsg->intreq->complete = intr_in_complete; -+ } -+ -+ fsg->running = 1; -+ for (i = 0; i < fsg->nluns; ++i) -+ fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; -+ return rc; -+} -+ -+ -+/* -+ * Change our operational configuration. This code must agree with the code -+ * that returns config descriptors, and with interface altsetting code. -+ * -+ * It's also responsible for power management interactions. Some -+ * configurations might not work with our current power sources. -+ * For now we just assume the gadget is always self-powered. -+ */ -+static int do_set_config(struct fsg_dev *fsg, u8 new_config) -+{ -+ int rc = 0; -+ -+ /* Disable the single interface */ -+ if (fsg->config != 0) { -+ DBG(fsg, "reset config\n"); -+ fsg->config = 0; -+ rc = do_set_interface(fsg, -1); -+ } -+ -+ /* Enable the interface */ -+ if (new_config != 0) { -+ fsg->config = new_config; -+ if ((rc = do_set_interface(fsg, 0)) != 0) -+ fsg->config = 0; // Reset on errors -+ else -+ INFO(fsg, "%s config #%d\n", -+ usb_speed_string(fsg->gadget->speed), -+ fsg->config); -+ } -+ return rc; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void handle_exception(struct fsg_dev *fsg) -+{ -+ siginfo_t info; -+ int sig; -+ int i; -+ int num_active; -+ struct fsg_buffhd *bh; -+ enum fsg_state old_state; -+ u8 new_config; -+ struct fsg_lun *curlun; -+ unsigned int exception_req_tag; -+ int rc; -+ -+ /* Clear the existing signals. Anything but SIGUSR1 is converted -+ * into a high-priority EXIT exception. */ -+ for (;;) { -+ sig = dequeue_signal_lock(current, ¤t->blocked, &info); -+ if (!sig) -+ break; -+ if (sig != SIGUSR1) { -+ if (fsg->state < FSG_STATE_EXIT) -+ DBG(fsg, "Main thread exiting on signal\n"); -+ raise_exception(fsg, FSG_STATE_EXIT); -+ } -+ } -+ -+ /* Cancel all the pending transfers */ -+ if (fsg->intreq_busy) -+ usb_ep_dequeue(fsg->intr_in, fsg->intreq); -+ for (i = 0; i < fsg_num_buffers; ++i) { -+ bh = &fsg->buffhds[i]; -+ if (bh->inreq_busy) -+ usb_ep_dequeue(fsg->bulk_in, bh->inreq); -+ if (bh->outreq_busy) -+ usb_ep_dequeue(fsg->bulk_out, bh->outreq); -+ } -+ -+ /* Wait until everything is idle */ -+ for (;;) { -+ num_active = fsg->intreq_busy; -+ for (i = 0; i < fsg_num_buffers; ++i) { -+ bh = &fsg->buffhds[i]; -+ num_active += bh->inreq_busy + bh->outreq_busy; -+ } -+ if (num_active == 0) -+ break; -+ if (sleep_thread(fsg)) -+ return; -+ } -+ -+ /* Clear out the controller's fifos */ -+ if (fsg->bulk_in_enabled) -+ usb_ep_fifo_flush(fsg->bulk_in); -+ if (fsg->bulk_out_enabled) -+ usb_ep_fifo_flush(fsg->bulk_out); -+ if (fsg->intr_in_enabled) -+ usb_ep_fifo_flush(fsg->intr_in); -+ -+ /* Reset the I/O buffer states and pointers, the SCSI -+ * state, and the exception. Then invoke the handler. */ -+ spin_lock_irq(&fsg->lock); -+ -+ for (i = 0; i < fsg_num_buffers; ++i) { -+ bh = &fsg->buffhds[i]; -+ bh->state = BUF_STATE_EMPTY; -+ } -+ fsg->next_buffhd_to_fill = fsg->next_buffhd_to_drain = -+ &fsg->buffhds[0]; -+ -+ exception_req_tag = fsg->exception_req_tag; -+ new_config = fsg->new_config; -+ old_state = fsg->state; -+ -+ if (old_state == FSG_STATE_ABORT_BULK_OUT) -+ fsg->state = FSG_STATE_STATUS_PHASE; -+ else { -+ for (i = 0; i < fsg->nluns; ++i) { -+ curlun = &fsg->luns[i]; -+ curlun->prevent_medium_removal = 0; -+ curlun->sense_data = curlun->unit_attention_data = -+ SS_NO_SENSE; -+ curlun->sense_data_info = 0; -+ curlun->info_valid = 0; -+ } -+ fsg->state = FSG_STATE_IDLE; -+ } -+ spin_unlock_irq(&fsg->lock); -+ -+ /* Carry out any extra actions required for the exception */ -+ switch (old_state) { -+ default: -+ break; -+ -+ case FSG_STATE_ABORT_BULK_OUT: -+ send_status(fsg); -+ spin_lock_irq(&fsg->lock); -+ if (fsg->state == FSG_STATE_STATUS_PHASE) -+ fsg->state = FSG_STATE_IDLE; -+ spin_unlock_irq(&fsg->lock); -+ break; -+ -+ case FSG_STATE_RESET: -+ /* In case we were forced against our will to halt a -+ * bulk endpoint, clear the halt now. (The SuperH UDC -+ * requires this.) */ -+ if (test_and_clear_bit(IGNORE_BULK_OUT, &fsg->atomic_bitflags)) -+ usb_ep_clear_halt(fsg->bulk_in); -+ -+ if (transport_is_bbb()) { -+ if (fsg->ep0_req_tag == exception_req_tag) -+ ep0_queue(fsg); // Complete the status stage -+ -+ } else if (transport_is_cbi()) -+ send_status(fsg); // Status by interrupt pipe -+ -+ /* Technically this should go here, but it would only be -+ * a waste of time. Ditto for the INTERFACE_CHANGE and -+ * CONFIG_CHANGE cases. */ -+ // for (i = 0; i < fsg->nluns; ++i) -+ // fsg->luns[i].unit_attention_data = SS_RESET_OCCURRED; -+ break; -+ -+ case FSG_STATE_INTERFACE_CHANGE: -+ rc = do_set_interface(fsg, 0); -+ if (fsg->ep0_req_tag != exception_req_tag) -+ break; -+ if (rc != 0) // STALL on errors -+ fsg_set_halt(fsg, fsg->ep0); -+ else // Complete the status stage -+ ep0_queue(fsg); -+ break; -+ -+ case FSG_STATE_CONFIG_CHANGE: -+ rc = do_set_config(fsg, new_config); -+ if (fsg->ep0_req_tag != exception_req_tag) -+ break; -+ if (rc != 0) // STALL on errors -+ fsg_set_halt(fsg, fsg->ep0); -+ else // Complete the status stage -+ ep0_queue(fsg); -+ break; -+ -+ case FSG_STATE_DISCONNECT: -+ for (i = 0; i < fsg->nluns; ++i) -+ fsg_lun_fsync_sub(fsg->luns + i); -+ do_set_config(fsg, 0); // Unconfigured state -+ break; -+ -+ case FSG_STATE_EXIT: -+ case FSG_STATE_TERMINATED: -+ do_set_config(fsg, 0); // Free resources -+ spin_lock_irq(&fsg->lock); -+ fsg->state = FSG_STATE_TERMINATED; // Stop the thread -+ spin_unlock_irq(&fsg->lock); -+ break; -+ } -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static int fsg_main_thread(void *fsg_) -+{ -+ struct fsg_dev *fsg = fsg_; -+ -+ /* Allow the thread to be killed by a signal, but set the signal mask -+ * to block everything but INT, TERM, KILL, and USR1. */ -+ allow_signal(SIGINT); -+ allow_signal(SIGTERM); -+ allow_signal(SIGKILL); -+ allow_signal(SIGUSR1); -+ -+ /* Allow the thread to be frozen */ -+ set_freezable(); -+ -+ /* Arrange for userspace references to be interpreted as kernel -+ * pointers. That way we can pass a kernel pointer to a routine -+ * that expects a __user pointer and it will work okay. */ -+ set_fs(get_ds()); -+ -+ /* The main loop */ -+ while (fsg->state != FSG_STATE_TERMINATED) { -+ if (exception_in_progress(fsg) || signal_pending(current)) { -+ handle_exception(fsg); -+ continue; -+ } -+ -+ if (!fsg->running) { -+ sleep_thread(fsg); -+ continue; -+ } -+ -+ if (get_next_command(fsg)) -+ continue; -+ -+ spin_lock_irq(&fsg->lock); -+ if (!exception_in_progress(fsg)) -+ fsg->state = FSG_STATE_DATA_PHASE; -+ spin_unlock_irq(&fsg->lock); -+ -+ if (do_scsi_command(fsg) || finish_reply(fsg)) -+ continue; -+ -+ spin_lock_irq(&fsg->lock); -+ if (!exception_in_progress(fsg)) -+ fsg->state = FSG_STATE_STATUS_PHASE; -+ spin_unlock_irq(&fsg->lock); -+ -+ if (send_status(fsg)) -+ continue; -+ -+ spin_lock_irq(&fsg->lock); -+ if (!exception_in_progress(fsg)) -+ fsg->state = FSG_STATE_IDLE; -+ spin_unlock_irq(&fsg->lock); -+ } -+ -+ spin_lock_irq(&fsg->lock); -+ fsg->thread_task = NULL; -+ spin_unlock_irq(&fsg->lock); -+ -+ /* If we are exiting because of a signal, unregister the -+ * gadget driver. */ -+ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) -+ usb_gadget_unregister_driver(&fsg_driver); -+ -+ /* Let the unbind and cleanup routines know the thread has exited */ -+ complete_and_exit(&fsg->thread_notifier, 0); -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+ -+/* The write permissions and store_xxx pointers are set in fsg_bind() */ -+static DEVICE_ATTR(ro, 0444, fsg_show_ro, NULL); -+static DEVICE_ATTR(nofua, 0644, fsg_show_nofua, NULL); -+static DEVICE_ATTR(file, 0444, fsg_show_file, NULL); -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void fsg_release(struct kref *ref) -+{ -+ struct fsg_dev *fsg = container_of(ref, struct fsg_dev, ref); -+ -+ kfree(fsg->luns); -+ kfree(fsg); -+} -+ -+static void lun_release(struct device *dev) -+{ -+ struct rw_semaphore *filesem = dev_get_drvdata(dev); -+ struct fsg_dev *fsg = -+ container_of(filesem, struct fsg_dev, filesem); -+ -+ kref_put(&fsg->ref, fsg_release); -+} -+ -+static void /* __init_or_exit */ fsg_unbind(struct usb_gadget *gadget) -+{ -+ struct fsg_dev *fsg = get_gadget_data(gadget); -+ int i; -+ struct fsg_lun *curlun; -+ struct usb_request *req = fsg->ep0req; -+ -+ DBG(fsg, "unbind\n"); -+ clear_bit(REGISTERED, &fsg->atomic_bitflags); -+ -+ /* If the thread isn't already dead, tell it to exit now */ -+ if (fsg->state != FSG_STATE_TERMINATED) { -+ raise_exception(fsg, FSG_STATE_EXIT); -+ wait_for_completion(&fsg->thread_notifier); -+ -+ /* The cleanup routine waits for this completion also */ -+ complete(&fsg->thread_notifier); -+ } -+ -+ /* Unregister the sysfs attribute files and the LUNs */ -+ for (i = 0; i < fsg->nluns; ++i) { -+ curlun = &fsg->luns[i]; -+ if (curlun->registered) { -+ device_remove_file(&curlun->dev, &dev_attr_nofua); -+ device_remove_file(&curlun->dev, &dev_attr_ro); -+ device_remove_file(&curlun->dev, &dev_attr_file); -+ fsg_lun_close(curlun); -+ device_unregister(&curlun->dev); -+ curlun->registered = 0; -+ } -+ } -+ -+ /* Free the data buffers */ -+ for (i = 0; i < fsg_num_buffers; ++i) -+ kfree(fsg->buffhds[i].buf); -+ -+ /* Free the request and buffer for endpoint 0 */ -+ if (req) { -+ kfree(req->buf); -+ usb_ep_free_request(fsg->ep0, req); -+ } -+ -+ set_gadget_data(gadget, NULL); -+} -+ -+ -+static int __init check_parameters(struct fsg_dev *fsg) -+{ -+ int prot; -+ int gcnum; -+ -+ /* Store the default values */ -+ mod_data.transport_type = USB_PR_BULK; -+ mod_data.transport_name = "Bulk-only"; -+ mod_data.protocol_type = USB_SC_SCSI; -+ mod_data.protocol_name = "Transparent SCSI"; -+ -+ /* Some peripheral controllers are known not to be able to -+ * halt bulk endpoints correctly. If one of them is present, -+ * disable stalls. -+ */ -+ if (gadget_is_at91(fsg->gadget)) -+ mod_data.can_stall = 0; -+ -+ if (mod_data.release == 0xffff) { // Parameter wasn't set -+ gcnum = usb_gadget_controller_number(fsg->gadget); -+ if (gcnum >= 0) -+ mod_data.release = 0x0300 + gcnum; -+ else { -+ WARNING(fsg, "controller '%s' not recognized\n", -+ fsg->gadget->name); -+ mod_data.release = 0x0399; -+ } -+ } -+ -+ prot = simple_strtol(mod_data.protocol_parm, NULL, 0); -+ -+#ifdef CONFIG_USB_FILE_STORAGE_TEST -+ if (strnicmp(mod_data.transport_parm, "BBB", 10) == 0) { -+ ; // Use default setting -+ } else if (strnicmp(mod_data.transport_parm, "CB", 10) == 0) { -+ mod_data.transport_type = USB_PR_CB; -+ mod_data.transport_name = "Control-Bulk"; -+ } else if (strnicmp(mod_data.transport_parm, "CBI", 10) == 0) { -+ mod_data.transport_type = USB_PR_CBI; -+ mod_data.transport_name = "Control-Bulk-Interrupt"; -+ } else { -+ ERROR(fsg, "invalid transport: %s\n", mod_data.transport_parm); -+ return -EINVAL; -+ } -+ -+ if (strnicmp(mod_data.protocol_parm, "SCSI", 10) == 0 || -+ prot == USB_SC_SCSI) { -+ ; // Use default setting -+ } else if (strnicmp(mod_data.protocol_parm, "RBC", 10) == 0 || -+ prot == USB_SC_RBC) { -+ mod_data.protocol_type = USB_SC_RBC; -+ mod_data.protocol_name = "RBC"; -+ } else if (strnicmp(mod_data.protocol_parm, "8020", 4) == 0 || -+ strnicmp(mod_data.protocol_parm, "ATAPI", 10) == 0 || -+ prot == USB_SC_8020) { -+ mod_data.protocol_type = USB_SC_8020; -+ mod_data.protocol_name = "8020i (ATAPI)"; -+ } else if (strnicmp(mod_data.protocol_parm, "QIC", 3) == 0 || -+ prot == USB_SC_QIC) { -+ mod_data.protocol_type = USB_SC_QIC; -+ mod_data.protocol_name = "QIC-157"; -+ } else if (strnicmp(mod_data.protocol_parm, "UFI", 10) == 0 || -+ prot == USB_SC_UFI) { -+ mod_data.protocol_type = USB_SC_UFI; -+ mod_data.protocol_name = "UFI"; -+ } else if (strnicmp(mod_data.protocol_parm, "8070", 4) == 0 || -+ prot == USB_SC_8070) { -+ mod_data.protocol_type = USB_SC_8070; -+ mod_data.protocol_name = "8070i"; -+ } else { -+ ERROR(fsg, "invalid protocol: %s\n", mod_data.protocol_parm); -+ return -EINVAL; -+ } -+ -+ mod_data.buflen &= PAGE_CACHE_MASK; -+ if (mod_data.buflen <= 0) { -+ ERROR(fsg, "invalid buflen\n"); -+ return -ETOOSMALL; -+ } -+ -+#endif /* CONFIG_USB_FILE_STORAGE_TEST */ -+ -+ /* Serial string handling. -+ * On a real device, the serial string would be loaded -+ * from permanent storage. */ -+ if (mod_data.serial) { -+ const char *ch; -+ unsigned len = 0; -+ -+ /* Sanity check : -+ * The CB[I] specification limits the serial string to -+ * 12 uppercase hexadecimal characters. -+ * BBB need at least 12 uppercase hexadecimal characters, -+ * with a maximum of 126. */ -+ for (ch = mod_data.serial; *ch; ++ch) { -+ ++len; -+ if ((*ch < '0' || *ch > '9') && -+ (*ch < 'A' || *ch > 'F')) { /* not uppercase hex */ -+ WARNING(fsg, -+ "Invalid serial string character: %c\n", -+ *ch); -+ goto no_serial; -+ } -+ } -+ if (len > 126 || -+ (mod_data.transport_type == USB_PR_BULK && len < 12) || -+ (mod_data.transport_type != USB_PR_BULK && len > 12)) { -+ WARNING(fsg, "Invalid serial string length!\n"); -+ goto no_serial; -+ } -+ fsg_strings[FSG_STRING_SERIAL - 1].s = mod_data.serial; -+ } else { -+ WARNING(fsg, "No serial-number string provided!\n"); -+ no_serial: -+ device_desc.iSerialNumber = 0; -+ } -+ -+ return 0; -+} -+ -+ -+static int __init fsg_bind(struct usb_gadget *gadget) -+{ -+ struct fsg_dev *fsg = the_fsg; -+ int rc; -+ int i; -+ struct fsg_lun *curlun; -+ struct usb_ep *ep; -+ struct usb_request *req; -+ char *pathbuf, *p; -+ -+ fsg->gadget = gadget; -+ set_gadget_data(gadget, fsg); -+ fsg->ep0 = gadget->ep0; -+ fsg->ep0->driver_data = fsg; -+ -+ if ((rc = check_parameters(fsg)) != 0) -+ goto out; -+ -+ if (mod_data.removable) { // Enable the store_xxx attributes -+ dev_attr_file.attr.mode = 0644; -+ dev_attr_file.store = fsg_store_file; -+ if (!mod_data.cdrom) { -+ dev_attr_ro.attr.mode = 0644; -+ dev_attr_ro.store = fsg_store_ro; -+ } -+ } -+ -+ /* Only for removable media? */ -+ dev_attr_nofua.attr.mode = 0644; -+ dev_attr_nofua.store = fsg_store_nofua; -+ -+ /* Find out how many LUNs there should be */ -+ i = mod_data.nluns; -+ if (i == 0) -+ i = max(mod_data.num_filenames, 1u); -+ if (i > FSG_MAX_LUNS) { -+ ERROR(fsg, "invalid number of LUNs: %d\n", i); -+ rc = -EINVAL; -+ goto out; -+ } -+ -+ /* Create the LUNs, open their backing files, and register the -+ * LUN devices in sysfs. */ -+ fsg->luns = kzalloc(i * sizeof(struct fsg_lun), GFP_KERNEL); -+ if (!fsg->luns) { -+ rc = -ENOMEM; -+ goto out; -+ } -+ fsg->nluns = i; -+ -+ for (i = 0; i < fsg->nluns; ++i) { -+ curlun = &fsg->luns[i]; -+ curlun->cdrom = !!mod_data.cdrom; -+ curlun->ro = mod_data.cdrom || mod_data.ro[i]; -+ curlun->initially_ro = curlun->ro; -+ curlun->removable = mod_data.removable; -+ curlun->nofua = mod_data.nofua[i]; -+ curlun->dev.release = lun_release; -+ curlun->dev.parent = &gadget->dev; -+ curlun->dev.driver = &fsg_driver.driver; -+ dev_set_drvdata(&curlun->dev, &fsg->filesem); -+ dev_set_name(&curlun->dev,"%s-lun%d", -+ dev_name(&gadget->dev), i); -+ -+ kref_get(&fsg->ref); -+ rc = device_register(&curlun->dev); -+ if (rc) { -+ INFO(fsg, "failed to register LUN%d: %d\n", i, rc); -+ put_device(&curlun->dev); -+ goto out; -+ } -+ curlun->registered = 1; -+ -+ rc = device_create_file(&curlun->dev, &dev_attr_ro); -+ if (rc) -+ goto out; -+ rc = device_create_file(&curlun->dev, &dev_attr_nofua); -+ if (rc) -+ goto out; -+ rc = device_create_file(&curlun->dev, &dev_attr_file); -+ if (rc) -+ goto out; -+ -+ if (mod_data.file[i] && *mod_data.file[i]) { -+ rc = fsg_lun_open(curlun, mod_data.file[i]); -+ if (rc) -+ goto out; -+ } else if (!mod_data.removable) { -+ ERROR(fsg, "no file given for LUN%d\n", i); -+ rc = -EINVAL; -+ goto out; -+ } -+ } -+ -+ /* Find all the endpoints we will use */ -+ usb_ep_autoconfig_reset(gadget); -+ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_in_desc); -+ if (!ep) -+ goto autoconf_fail; -+ ep->driver_data = fsg; // claim the endpoint -+ fsg->bulk_in = ep; -+ -+ ep = usb_ep_autoconfig(gadget, &fsg_fs_bulk_out_desc); -+ if (!ep) -+ goto autoconf_fail; -+ ep->driver_data = fsg; // claim the endpoint -+ fsg->bulk_out = ep; -+ -+ if (transport_is_cbi()) { -+ ep = usb_ep_autoconfig(gadget, &fsg_fs_intr_in_desc); -+ if (!ep) -+ goto autoconf_fail; -+ ep->driver_data = fsg; // claim the endpoint -+ fsg->intr_in = ep; -+ } -+ -+ /* Fix up the descriptors */ -+ device_desc.idVendor = cpu_to_le16(mod_data.vendor); -+ device_desc.idProduct = cpu_to_le16(mod_data.product); -+ device_desc.bcdDevice = cpu_to_le16(mod_data.release); -+ -+ i = (transport_is_cbi() ? 3 : 2); // Number of endpoints -+ fsg_intf_desc.bNumEndpoints = i; -+ fsg_intf_desc.bInterfaceSubClass = mod_data.protocol_type; -+ fsg_intf_desc.bInterfaceProtocol = mod_data.transport_type; -+ fsg_fs_function[i + FSG_FS_FUNCTION_PRE_EP_ENTRIES] = NULL; -+ -+ if (gadget_is_dualspeed(gadget)) { -+ fsg_hs_function[i + FSG_HS_FUNCTION_PRE_EP_ENTRIES] = NULL; -+ -+ /* Assume endpoint addresses are the same for both speeds */ -+ fsg_hs_bulk_in_desc.bEndpointAddress = -+ fsg_fs_bulk_in_desc.bEndpointAddress; -+ fsg_hs_bulk_out_desc.bEndpointAddress = -+ fsg_fs_bulk_out_desc.bEndpointAddress; -+ fsg_hs_intr_in_desc.bEndpointAddress = -+ fsg_fs_intr_in_desc.bEndpointAddress; -+ } -+ -+ if (gadget_is_superspeed(gadget)) { -+ unsigned max_burst; -+ -+ fsg_ss_function[i + FSG_SS_FUNCTION_PRE_EP_ENTRIES] = NULL; -+ -+ /* Calculate bMaxBurst, we know packet size is 1024 */ -+ max_burst = min_t(unsigned, mod_data.buflen / 1024, 15); -+ -+ /* Assume endpoint addresses are the same for both speeds */ -+ fsg_ss_bulk_in_desc.bEndpointAddress = -+ fsg_fs_bulk_in_desc.bEndpointAddress; -+ fsg_ss_bulk_in_comp_desc.bMaxBurst = max_burst; -+ -+ fsg_ss_bulk_out_desc.bEndpointAddress = -+ fsg_fs_bulk_out_desc.bEndpointAddress; -+ fsg_ss_bulk_out_comp_desc.bMaxBurst = max_burst; -+ } -+ -+ if (gadget_is_otg(gadget)) -+ fsg_otg_desc.bmAttributes |= USB_OTG_HNP; -+ -+ rc = -ENOMEM; -+ -+ /* Allocate the request and buffer for endpoint 0 */ -+ fsg->ep0req = req = usb_ep_alloc_request(fsg->ep0, GFP_KERNEL); -+ if (!req) -+ goto out; -+ req->buf = kmalloc(EP0_BUFSIZE, GFP_KERNEL); -+ if (!req->buf) -+ goto out; -+ req->complete = ep0_complete; -+ -+ /* Allocate the data buffers */ -+ for (i = 0; i < fsg_num_buffers; ++i) { -+ struct fsg_buffhd *bh = &fsg->buffhds[i]; -+ -+ /* Allocate for the bulk-in endpoint. We assume that -+ * the buffer will also work with the bulk-out (and -+ * interrupt-in) endpoint. */ -+ bh->buf = kmalloc(mod_data.buflen, GFP_KERNEL); -+ if (!bh->buf) -+ goto out; -+ bh->next = bh + 1; -+ } -+ fsg->buffhds[fsg_num_buffers - 1].next = &fsg->buffhds[0]; -+ -+ /* This should reflect the actual gadget power source */ -+ usb_gadget_set_selfpowered(gadget); -+ -+ snprintf(fsg_string_manufacturer, sizeof fsg_string_manufacturer, -+ "%s %s with %s", -+ init_utsname()->sysname, init_utsname()->release, -+ gadget->name); -+ -+ fsg->thread_task = kthread_create(fsg_main_thread, fsg, -+ "file-storage-gadget"); -+ if (IS_ERR(fsg->thread_task)) { -+ rc = PTR_ERR(fsg->thread_task); -+ goto out; -+ } -+ -+ INFO(fsg, DRIVER_DESC ", version: " DRIVER_VERSION "\n"); -+ INFO(fsg, "NOTE: This driver is deprecated. " -+ "Consider using g_mass_storage instead.\n"); -+ INFO(fsg, "Number of LUNs=%d\n", fsg->nluns); -+ -+ pathbuf = kmalloc(PATH_MAX, GFP_KERNEL); -+ for (i = 0; i < fsg->nluns; ++i) { -+ curlun = &fsg->luns[i]; -+ if (fsg_lun_is_open(curlun)) { -+ p = NULL; -+ if (pathbuf) { -+ p = d_path(&curlun->filp->f_path, -+ pathbuf, PATH_MAX); -+ if (IS_ERR(p)) -+ p = NULL; -+ } -+ LINFO(curlun, "ro=%d, nofua=%d, file: %s\n", -+ curlun->ro, curlun->nofua, (p ? p : "(error)")); -+ } -+ } -+ kfree(pathbuf); -+ -+ DBG(fsg, "transport=%s (x%02x)\n", -+ mod_data.transport_name, mod_data.transport_type); -+ DBG(fsg, "protocol=%s (x%02x)\n", -+ mod_data.protocol_name, mod_data.protocol_type); -+ DBG(fsg, "VendorID=x%04x, ProductID=x%04x, Release=x%04x\n", -+ mod_data.vendor, mod_data.product, mod_data.release); -+ DBG(fsg, "removable=%d, stall=%d, cdrom=%d, buflen=%u\n", -+ mod_data.removable, mod_data.can_stall, -+ mod_data.cdrom, mod_data.buflen); -+ DBG(fsg, "I/O thread pid: %d\n", task_pid_nr(fsg->thread_task)); -+ -+ set_bit(REGISTERED, &fsg->atomic_bitflags); -+ -+ /* Tell the thread to start working */ -+ wake_up_process(fsg->thread_task); -+ return 0; -+ -+autoconf_fail: -+ ERROR(fsg, "unable to autoconfigure all endpoints\n"); -+ rc = -ENOTSUPP; -+ -+out: -+ fsg->state = FSG_STATE_TERMINATED; // The thread is dead -+ fsg_unbind(gadget); -+ complete(&fsg->thread_notifier); -+ return rc; -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static void fsg_suspend(struct usb_gadget *gadget) -+{ -+ struct fsg_dev *fsg = get_gadget_data(gadget); -+ -+ DBG(fsg, "suspend\n"); -+ set_bit(SUSPENDED, &fsg->atomic_bitflags); -+} -+ -+static void fsg_resume(struct usb_gadget *gadget) -+{ -+ struct fsg_dev *fsg = get_gadget_data(gadget); -+ -+ DBG(fsg, "resume\n"); -+ clear_bit(SUSPENDED, &fsg->atomic_bitflags); -+} -+ -+ -+/*-------------------------------------------------------------------------*/ -+ -+static struct usb_gadget_driver fsg_driver = { -+ .max_speed = USB_SPEED_SUPER, -+ .function = (char *) fsg_string_product, -+ .unbind = fsg_unbind, -+ .disconnect = fsg_disconnect, -+ .setup = fsg_setup, -+ .suspend = fsg_suspend, -+ .resume = fsg_resume, -+ -+ .driver = { -+ .name = DRIVER_NAME, -+ .owner = THIS_MODULE, -+ // .release = ... -+ // .suspend = ... -+ // .resume = ... -+ }, -+}; -+ -+ -+static int __init fsg_alloc(void) -+{ -+ struct fsg_dev *fsg; -+ -+ fsg = kzalloc(sizeof *fsg + -+ fsg_num_buffers * sizeof *(fsg->buffhds), GFP_KERNEL); -+ -+ if (!fsg) -+ return -ENOMEM; -+ spin_lock_init(&fsg->lock); -+ init_rwsem(&fsg->filesem); -+ kref_init(&fsg->ref); -+ init_completion(&fsg->thread_notifier); -+ -+ the_fsg = fsg; -+ return 0; -+} -+ -+ -+static int __init fsg_init(void) -+{ -+ int rc; -+ struct fsg_dev *fsg; -+ -+ rc = fsg_num_buffers_validate(); -+ if (rc != 0) -+ return rc; -+ -+ if ((rc = fsg_alloc()) != 0) -+ return rc; -+ fsg = the_fsg; -+ if ((rc = usb_gadget_probe_driver(&fsg_driver, fsg_bind)) != 0) -+ kref_put(&fsg->ref, fsg_release); -+ return rc; -+} -+module_init(fsg_init); -+ -+ -+static void __exit fsg_cleanup(void) -+{ -+ struct fsg_dev *fsg = the_fsg; -+ -+ /* Unregister the driver iff the thread hasn't already done so */ -+ if (test_and_clear_bit(REGISTERED, &fsg->atomic_bitflags)) -+ usb_gadget_unregister_driver(&fsg_driver); -+ -+ /* Wait for the thread to finish up */ -+ wait_for_completion(&fsg->thread_notifier); -+ -+ kref_put(&fsg->ref, fsg_release); -+} -+module_exit(fsg_cleanup); -diff --git a/drivers/usb/host/Kconfig b/drivers/usb/host/Kconfig -index 16758b12a5e9..37a8bcf35ec2 100644 ---- a/drivers/usb/host/Kconfig -+++ b/drivers/usb/host/Kconfig -@@ -748,6 +748,16 @@ config USB_HWA_HCD - To compile this driver a module, choose M here: the module - will be called "hwa-hc". - -+config USB_DWCOTG -+ bool "Synopsis DWC host support" -+ depends on USB && (FIQ || ARM64) -+ help -+ The Synopsis DWC controller is a dual-role -+ host/peripheral/OTG ("On The Go") USB controllers. -+ -+ Enable this option to support this IP in host controller mode. -+ If unsure, say N. -+ - config USB_IMX21_HCD - tristate "i.MX21 HCD support" - depends on ARM && ARCH_MXC -diff --git a/drivers/usb/host/Makefile b/drivers/usb/host/Makefile -index 84514f71ae44..31bc2d78a4c3 100644 ---- a/drivers/usb/host/Makefile -+++ b/drivers/usb/host/Makefile -@@ -83,6 +83,8 @@ obj-$(CONFIG_USB_SL811_CS) += sl811_cs.o - obj-$(CONFIG_USB_U132_HCD) += u132-hcd.o - obj-$(CONFIG_USB_R8A66597_HCD) += r8a66597-hcd.o - obj-$(CONFIG_USB_HWA_HCD) += hwa-hc.o -+ -+obj-$(CONFIG_USB_DWCOTG) += dwc_otg/ dwc_common_port/ - obj-$(CONFIG_USB_IMX21_HCD) += imx21-hcd.o - obj-$(CONFIG_USB_FSL_USB2) += fsl-mph-dr-of.o - obj-$(CONFIG_USB_EHCI_FSL) += fsl-mph-dr-of.o -diff --git a/drivers/usb/host/dwc_common_port/Makefile b/drivers/usb/host/dwc_common_port/Makefile -new file mode 100644 -index 000000000000..f10d466d1aea ---- /dev/null -+++ b/drivers/usb/host/dwc_common_port/Makefile -@@ -0,0 +1,58 @@ -+# -+# Makefile for DWC_common library -+# -+ -+ifneq ($(KERNELRELEASE),) -+ -+ccflags-y += -DDWC_LINUX -+#ccflags-y += -DDEBUG -+#ccflags-y += -DDWC_DEBUG_REGS -+#ccflags-y += -DDWC_DEBUG_MEMORY -+ -+ccflags-y += -DDWC_LIBMODULE -+ccflags-y += -DDWC_CCLIB -+#ccflags-y += -DDWC_CRYPTOLIB -+ccflags-y += -DDWC_NOTIFYLIB -+ccflags-y += -DDWC_UTFLIB -+ -+obj-$(CONFIG_USB_DWCOTG) += dwc_common_port_lib.o -+dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \ -+ dwc_crypto.o dwc_notifier.o \ -+ dwc_common_linux.o dwc_mem.o -+ -+kernrelwd := $(subst ., ,$(KERNELRELEASE)) -+kernrel3 := $(word 1,$(kernrelwd)).$(word 2,$(kernrelwd)).$(word 3,$(kernrelwd)) -+ -+ifneq ($(kernrel3),2.6.20) -+# grayg - I only know that we use ccflags-y in 2.6.31 actually -+ccflags-y += $(CPPFLAGS) -+endif -+ -+else -+ -+#ifeq ($(KDIR),) -+#$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment) -+#endif -+ -+ifeq ($(ARCH),) -+$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \ -+ cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-") -+endif -+ -+ifeq ($(DOXYGEN),) -+DOXYGEN := doxygen -+endif -+ -+default: -+ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules -+ -+docs: $(wildcard *.[hc]) doc/doxygen.cfg -+ $(DOXYGEN) doc/doxygen.cfg -+ -+tags: $(wildcard *.[hc]) -+ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h) -+ -+endif -+ -+clean: -+ rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/ -diff --git a/drivers/usb/host/dwc_common_port/Makefile.fbsd b/drivers/usb/host/dwc_common_port/Makefile.fbsd -new file mode 100644 -index 000000000000..45db9915b9d3 ---- /dev/null -+++ b/drivers/usb/host/dwc_common_port/Makefile.fbsd -@@ -0,0 +1,17 @@ -+CFLAGS += -I/sys/i386/compile/GENERIC -I/sys/i386/include -I/usr/include -+CFLAGS += -DDWC_FREEBSD -+CFLAGS += -DDEBUG -+#CFLAGS += -DDWC_DEBUG_REGS -+#CFLAGS += -DDWC_DEBUG_MEMORY -+ -+#CFLAGS += -DDWC_LIBMODULE -+#CFLAGS += -DDWC_CCLIB -+#CFLAGS += -DDWC_CRYPTOLIB -+#CFLAGS += -DDWC_NOTIFYLIB -+#CFLAGS += -DDWC_UTFLIB -+ -+KMOD = dwc_common_port_lib -+SRCS = dwc_cc.c dwc_modpow.c dwc_dh.c dwc_crypto.c dwc_notifier.c \ -+ dwc_common_fbsd.c dwc_mem.c -+ -+.include <bsd.kmod.mk> -diff --git a/drivers/usb/host/dwc_common_port/Makefile.linux b/drivers/usb/host/dwc_common_port/Makefile.linux -new file mode 100644 -index 000000000000..0cef7b461bd5 ---- /dev/null -+++ b/drivers/usb/host/dwc_common_port/Makefile.linux -@@ -0,0 +1,49 @@ -+# -+# Makefile for DWC_common library -+# -+ifneq ($(KERNELRELEASE),) -+ -+ccflags-y += -DDWC_LINUX -+#ccflags-y += -DDEBUG -+#ccflags-y += -DDWC_DEBUG_REGS -+#ccflags-y += -DDWC_DEBUG_MEMORY -+ -+ccflags-y += -DDWC_LIBMODULE -+ccflags-y += -DDWC_CCLIB -+ccflags-y += -DDWC_CRYPTOLIB -+ccflags-y += -DDWC_NOTIFYLIB -+ccflags-y += -DDWC_UTFLIB -+ -+obj-m := dwc_common_port_lib.o -+dwc_common_port_lib-objs := dwc_cc.o dwc_modpow.o dwc_dh.o \ -+ dwc_crypto.o dwc_notifier.o \ -+ dwc_common_linux.o dwc_mem.o -+ -+else -+ -+ifeq ($(KDIR),) -+$(error Must give "KDIR=/path/to/kernel/source" on command line or in environment) -+endif -+ -+ifeq ($(ARCH),) -+$(error Must give "ARCH=<arch>" on command line or in environment. Also, if \ -+ cross-compiling, must give "CROSS_COMPILE=/path/to/compiler/plus/tool-prefix-") -+endif -+ -+ifeq ($(DOXYGEN),) -+DOXYGEN := doxygen -+endif -+ -+default: -+ $(MAKE) -C$(KDIR) M=$(PWD) ARCH=$(ARCH) CROSS_COMPILE=$(CROSS_COMPILE) modules -+ -+docs: $(wildcard *.[hc]) doc/doxygen.cfg -+ $(DOXYGEN) doc/doxygen.cfg -+ -+tags: $(wildcard *.[hc]) -+ $(CTAGS) -e $(wildcard *.[hc]) $(wildcard linux/*.[hc]) $(wildcard $(KDIR)/include/linux/usb*.h) -+ -+endif -+ -+clean: -+ rm -rf *.o *.ko .*.cmd *.mod.c .*.o.d .*.o.tmp modules.order Module.markers Module.symvers .tmp_versions/ -diff --git a/drivers/usb/host/dwc_common_port/changes.txt b/drivers/usb/host/dwc_common_port/changes.txt -new file mode 100644 -index 000000000000..f6839f92c276 ---- /dev/null -+++ b/drivers/usb/host/dwc_common_port/changes.txt -@@ -0,0 +1,174 @@ -+ -+dwc_read_reg32() and friends now take an additional parameter, a pointer to an -+IO context struct. The IO context struct should live in an os-dependent struct -+in your driver. As an example, the dwc_usb3 driver has an os-dependent struct -+named 'os_dep' embedded in the main device struct. So there these calls look -+like this: -+ -+ dwc_read_reg32(&usb3_dev->os_dep.ioctx, &pcd->dev_global_regs->dcfg); -+ -+ dwc_write_reg32(&usb3_dev->os_dep.ioctx, -+ &pcd->dev_global_regs->dcfg, 0); -+ -+Note that for the existing Linux driver ports, it is not necessary to actually -+define the 'ioctx' member in the os-dependent struct. Since Linux does not -+require an IO context, its macros for dwc_read_reg32() and friends do not -+use the context pointer, so it is optimized away by the compiler. But it is -+necessary to add the pointer parameter to all of the call sites, to be ready -+for any future ports (such as FreeBSD) which do require an IO context. -+ -+ -+Similarly, dwc_alloc(), dwc_alloc_atomic(), dwc_strdup(), and dwc_free() now -+take an additional parameter, a pointer to a memory context. Examples: -+ -+ addr = dwc_alloc(&usb3_dev->os_dep.memctx, size); -+ -+ dwc_free(&usb3_dev->os_dep.memctx, addr); -+ -+Again, for the Linux ports, it is not necessary to actually define the memctx -+member, but it is necessary to add the pointer parameter to all of the call -+sites. -+ -+ -+Same for dwc_dma_alloc() and dwc_dma_free(). Examples: -+ -+ virt_addr = dwc_dma_alloc(&usb3_dev->os_dep.dmactx, size, &phys_addr); -+ -+ dwc_dma_free(&usb3_dev->os_dep.dmactx, size, virt_addr, phys_addr); -+ -+ -+Same for dwc_mutex_alloc() and dwc_mutex_free(). Examples: -+ -+ mutex = dwc_mutex_alloc(&usb3_dev->os_dep.mtxctx); -+ -+ dwc_mutex_free(&usb3_dev->os_dep.mtxctx, mutex); -+ -+ -+Same for dwc_spinlock_alloc() and dwc_spinlock_free(). Examples: -+ -+ lock = dwc_spinlock_alloc(&usb3_dev->osdep.splctx); -+ -+ dwc_spinlock_free(&usb3_dev->osdep.splctx, lock); -+ -+ -+Same for dwc_timer_alloc(). Example: -+ -+ timer = dwc_timer_alloc(&usb3_dev->os_dep.tmrctx, "dwc_usb3_tmr1", -+ cb_func, cb_data); -+ -+ -+Same for dwc_waitq_alloc(). Example: -+ -+ waitq = dwc_waitq_alloc(&usb3_dev->os_dep.wtqctx); -+ -+ -+Same for dwc_thread_run(). Example: -+ -+ thread = dwc_thread_run(&usb3_dev->os_dep.thdctx, func, -+ "dwc_usb3_thd1", data); -+ -+ -+Same for dwc_workq_alloc(). Example: -+ -+ workq = dwc_workq_alloc(&usb3_dev->osdep.wkqctx, "dwc_usb3_wkq1"); -+ -+ -+Same for dwc_task_alloc(). Example: -+ -+ task = dwc_task_alloc(&usb3_dev->os_dep.tskctx, "dwc_usb3_tsk1", -+ cb_func, cb_data); -+ -+ -+In addition to the context pointer additions, a few core functions have had -+other changes made to their parameters: -+ -+The 'flags' parameter to dwc_spinlock_irqsave() and dwc_spinunlock_irqrestore() -+has been changed from a uint64_t to a dwc_irqflags_t. -+ -+dwc_thread_should_stop() now takes a 'dwc_thread_t *' parameter, because the -+FreeBSD equivalent of that function requires it. -+ -+And, in addition to the context pointer, dwc_task_alloc() also adds a -+'char *name' parameter, to be consistent with dwc_thread_run() and -+dwc_workq_alloc(), and because the FreeBSD equivalent of that function -+requires a unique name. -+ -+ -+Here is a complete list of the core functions that now take a pointer to a -+context as their first parameter: -+ -+ dwc_read_reg32 -+ dwc_read_reg64 -+ dwc_write_reg32 -+ dwc_write_reg64 -+ dwc_modify_reg32 -+ dwc_modify_reg64 -+ dwc_alloc -+ dwc_alloc_atomic -+ dwc_strdup -+ dwc_free -+ dwc_dma_alloc -+ dwc_dma_free -+ dwc_mutex_alloc -+ dwc_mutex_free -+ dwc_spinlock_alloc -+ dwc_spinlock_free -+ dwc_timer_alloc -+ dwc_waitq_alloc -+ dwc_thread_run -+ dwc_workq_alloc -+ dwc_task_alloc Also adds a 'char *name' as its 2nd parameter -+ -+And here are the core functions that have other changes to their parameters: -+ -+ dwc_spinlock_irqsave 'flags' param is now a 'dwc_irqflags_t *' -+ dwc_spinunlock_irqrestore 'flags' param is now a 'dwc_irqflags_t' -+ dwc_thread_should_stop Adds a 'dwc_thread_t *' parameter -+ -+ -+ -+The changes to the core functions also require some of the other library -+functions to change: -+ -+ dwc_cc_if_alloc() and dwc_cc_if_free() now take a 'void *memctx' -+ (for memory allocation) as the 1st param and a 'void *mtxctx' -+ (for mutex allocation) as the 2nd param. -+ -+ dwc_cc_clear(), dwc_cc_add(), dwc_cc_change(), dwc_cc_remove(), -+ dwc_cc_data_for_save(), and dwc_cc_restore_from_data() now take a -+ 'void *memctx' as the 1st param. -+ -+ dwc_dh_modpow(), dwc_dh_pk(), and dwc_dh_derive_keys() now take a -+ 'void *memctx' as the 1st param. -+ -+ dwc_modpow() now takes a 'void *memctx' as the 1st param. -+ -+ dwc_alloc_notification_manager() now takes a 'void *memctx' as the -+ 1st param and a 'void *wkqctx' (for work queue allocation) as the 2nd -+ param, and also now returns an integer value that is non-zero if -+ allocation of its data structures or work queue fails. -+ -+ dwc_register_notifier() now takes a 'void *memctx' as the 1st param. -+ -+ dwc_memory_debug_start() now takes a 'void *mem_ctx' as the first -+ param, and also now returns an integer value that is non-zero if -+ allocation of its data structures fails. -+ -+ -+ -+Other miscellaneous changes: -+ -+The DEBUG_MEMORY and DEBUG_REGS #define's have been renamed to -+DWC_DEBUG_MEMORY and DWC_DEBUG_REGS. -+ -+The following #define's have been added to allow selectively compiling library -+features: -+ -+ DWC_CCLIB -+ DWC_CRYPTOLIB -+ DWC_NOTIFYLIB -+ DWC_UTFLIB -+ -+A DWC_LIBMODULE #define has also been added. If this is not defined, then the -+module code in dwc_common_linux.c is not compiled in. This allows linking the -+library code directly into a driver module, instead of as a standalone module. -diff --git a/drivers/usb/host/dwc_common_port/doc/doxygen.cfg b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg -new file mode 100644 -index 000000000000..89aa887af29d ---- /dev/null -+++ b/drivers/usb/host/dwc_common_port/doc/doxygen.cfg -@@ -0,0 +1,270 @@ -+# Doxyfile 1.4.5 -+ -+#--------------------------------------------------------------------------- -+# Project related configuration options -+#--------------------------------------------------------------------------- -+PROJECT_NAME = "Synopsys DWC Portability and Common Library for UWB" -+PROJECT_NUMBER = -+OUTPUT_DIRECTORY = doc -+CREATE_SUBDIRS = NO -+OUTPUT_LANGUAGE = English -+BRIEF_MEMBER_DESC = YES -+REPEAT_BRIEF = YES -+ABBREVIATE_BRIEF = "The $name class" \ -+ "The $name widget" \ -+ "The $name file" \ -+ is \ -+ provides \ -+ specifies \ -+ contains \ -+ represents \ -+ a \ -+ an \ -+ the -+ALWAYS_DETAILED_SEC = YES -+INLINE_INHERITED_MEMB = NO -+FULL_PATH_NAMES = NO -+STRIP_FROM_PATH = .. -+STRIP_FROM_INC_PATH = -+SHORT_NAMES = NO -+JAVADOC_AUTOBRIEF = YES -+MULTILINE_CPP_IS_BRIEF = NO -+DETAILS_AT_TOP = YES -+INHERIT_DOCS = YES -+SEPARATE_MEMBER_PAGES = NO -+TAB_SIZE = 8 -+ALIASES = -+OPTIMIZE_OUTPUT_FOR_C = YES -+OPTIMIZE_OUTPUT_JAVA = NO -+BUILTIN_STL_SUPPORT = NO -+DISTRIBUTE_GROUP_DOC = NO -+SUBGROUPING = NO -+#--------------------------------------------------------------------------- -+# Build related configuration options -+#--------------------------------------------------------------------------- -+EXTRACT_ALL = NO -+EXTRACT_PRIVATE = NO -+EXTRACT_STATIC = YES -+EXTRACT_LOCAL_CLASSES = NO -+EXTRACT_LOCAL_METHODS = NO -+HIDE_UNDOC_MEMBERS = NO -+HIDE_UNDOC_CLASSES = NO -+HIDE_FRIEND_COMPOUNDS = NO -+HIDE_IN_BODY_DOCS = NO -+INTERNAL_DOCS = NO -+CASE_SENSE_NAMES = YES -+HIDE_SCOPE_NAMES = NO -+SHOW_INCLUDE_FILES = NO -+INLINE_INFO = YES -+SORT_MEMBER_DOCS = NO -+SORT_BRIEF_DOCS = NO -+SORT_BY_SCOPE_NAME = NO -+GENERATE_TODOLIST = YES -+GENERATE_TESTLIST = YES -+GENERATE_BUGLIST = YES -+GENERATE_DEPRECATEDLIST= YES -+ENABLED_SECTIONS = -+MAX_INITIALIZER_LINES = 30 -+SHOW_USED_FILES = YES -+SHOW_DIRECTORIES = YES -+FILE_VERSION_FILTER = -+#--------------------------------------------------------------------------- -+# configuration options related to warning and progress messages -+#--------------------------------------------------------------------------- -+QUIET = YES -+WARNINGS = YES -+WARN_IF_UNDOCUMENTED = NO -+WARN_IF_DOC_ERROR = YES -+WARN_NO_PARAMDOC = YES -+WARN_FORMAT = "$file:$line: $text" -+WARN_LOGFILE = -+#--------------------------------------------------------------------------- -+# configuration options related to the input files -+#--------------------------------------------------------------------------- -+INPUT = . -+FILE_PATTERNS = *.c \ -+ *.cc \ -+ *.cxx \ -+ *.cpp \ -+ *.c++ \ -+ *.d \ -+ *.java \ -+ *.ii \ -+ *.ixx \ -+ *.ipp \ -+ *.i++ \ -+ *.inl \ -+ *.h \ -+ *.hh \ -+ *.hxx \ -+ *.hpp \ -+ *.h++ \ -+ *.idl \ -+ *.odl \ -+ *.cs \ -+ *.php \ -+ *.php3 \ -+ *.inc \ -+ *.m \ -+ *.mm \ -+ *.dox \ -+ *.py \ -+ *.C \ -+ *.CC \ -+ *.C++ \ -+ *.II \ -+ *.I++ \ -+ *.H \ -+ *.HH \ -+ *.H++ \ -+ *.CS \ -+ *.PHP \ -+ *.PHP3 \ -+ *.M \ -+ *.MM \ -+ *.PY -+RECURSIVE = NO -+EXCLUDE = -+EXCLUDE_SYMLINKS = NO -+EXCLUDE_PATTERNS = -+EXAMPLE_PATH = -+EXAMPLE_PATTERNS = * -+EXAMPLE_RECURSIVE = NO -+IMAGE_PATH = -+INPUT_FILTER = -+FILTER_PATTERNS = -+FILTER_SOURCE_FILES = NO -+#--------------------------------------------------------------------------- -+# configuration options related to source browsing -+#--------------------------------------------------------------------------- -+SOURCE_BROWSER = NO -+INLINE_SOURCES = NO -+STRIP_CODE_COMMENTS = YES -+REFERENCED_BY_RELATION = YES -+REFERENCES_RELATION = YES -+USE_HTAGS = NO -+VERBATIM_HEADERS = NO -+#--------------------------------------------------------------------------- -+# configuration options related to the alphabetical class index -+#--------------------------------------------------------------------------- -+ALPHABETICAL_INDEX = NO -+COLS_IN_ALPHA_INDEX = 5 -+IGNORE_PREFIX = -+#--------------------------------------------------------------------------- -+# configuration options related to the HTML output -+#--------------------------------------------------------------------------- -+GENERATE_HTML = YES -+HTML_OUTPUT = html -+HTML_FILE_EXTENSION = .html -+HTML_HEADER = -+HTML_FOOTER = -+HTML_STYLESHEET = -+HTML_ALIGN_MEMBERS = YES -+GENERATE_HTMLHELP = NO -+CHM_FILE = -+HHC_LOCATION = -+GENERATE_CHI = NO -+BINARY_TOC = NO -+TOC_EXPAND = NO -+DISABLE_INDEX = NO -+ENUM_VALUES_PER_LINE = 4 -+GENERATE_TREEVIEW = YES -+TREEVIEW_WIDTH = 250 -+#--------------------------------------------------------------------------- -+# configuration options related to the LaTeX output -+#--------------------------------------------------------------------------- -+GENERATE_LATEX = NO -+LATEX_OUTPUT = latex -+LATEX_CMD_NAME = latex -+MAKEINDEX_CMD_NAME = makeindex -+COMPACT_LATEX = NO -+PAPER_TYPE = a4wide -+EXTRA_PACKAGES = -+LATEX_HEADER = -+PDF_HYPERLINKS = NO -+USE_PDFLATEX = NO -+LATEX_BATCHMODE = NO -+LATEX_HIDE_INDICES = NO -+#--------------------------------------------------------------------------- -+# configuration options related to the RTF output -+#--------------------------------------------------------------------------- -+GENERATE_RTF = NO -+RTF_OUTPUT = rtf -+COMPACT_RTF = NO -+RTF_HYPERLINKS = NO -+RTF_STYLESHEET_FILE = -+RTF_EXTENSIONS_FILE = -+#--------------------------------------------------------------------------- -+# configuration options related to the man page output -+#--------------------------------------------------------------------------- -+GENERATE_MAN = NO -+MAN_OUTPUT = man -+MAN_EXTENSION = .3 -+MAN_LINKS = NO -+#--------------------------------------------------------------------------- -+# configuration options related to the XML output -+#--------------------------------------------------------------------------- -+GENERATE_XML = NO -+XML_OUTPUT = xml -+XML_SCHEMA = -+XML_DTD = -+XML_PROGRAMLISTING = YES -+#--------------------------------------------------------------------------- -+# configuration options for the AutoGen Definitions output -+#--------------------------------------------------------------------------- -+GENERATE_AUTOGEN_DEF = NO -+#--------------------------------------------------------------------------- -+# configuration options related to the Perl module output -+#--------------------------------------------------------------------------- -+GENERATE_PERLMOD = NO -+PERLMOD_LATEX = NO -+PERLMOD_PRETTY = YES -+PERLMOD_MAKEVAR_PREFIX = -+#--------------------------------------------------------------------------- -+# Configuration options related to the preprocessor -+#--------------------------------------------------------------------------- -+ENABLE_PREPROCESSING = YES -+MACRO_EXPANSION = NO -+EXPAND_ONLY_PREDEF = NO -+SEARCH_INCLUDES = YES -+INCLUDE_PATH = -+INCLUDE_FILE_PATTERNS = -+PREDEFINED = DEBUG DEBUG_MEMORY -+EXPAND_AS_DEFINED = -+SKIP_FUNCTION_MACROS = YES -+#--------------------------------------------------------------------------- -+# Configuration::additions related to external references -+#--------------------------------------------------------------------------- -+TAGFILES = -+GENERATE_TAGFILE = -+ALLEXTERNALS = NO -+EXTERNAL_GROUPS = YES -+PERL_PATH = /usr/bin/perl -+#--------------------------------------------------------------------------- -+# Configuration options related to the dot tool -+#--------------------------------------------------------------------------- -+CLASS_DIAGRAMS = YES -+HIDE_UNDOC_RELATIONS = YES -+HAVE_DOT = NO -+CLASS_GRAPH = YES -+COLLABORATION_GRAPH = YES -+GROUP_GRAPHS = YES -+UML_LOOK = NO -+TEMPLATE_RELATIONS = NO -+INCLUDE_GRAPH = NO -+INCLUDED_BY_GRAPH = YES -+CALL_GRAPH = NO -+GRAPHICAL_HIERARCHY = YES -+DIRECTORY_GRAPH = YES -+DOT_IMAGE_FORMAT = png -+DOT_PATH = -+DOTFILE_DIRS = -+MAX_DOT_GRAPH_DEPTH = 1000 -+DOT_TRANSPARENT = NO -+DOT_MULTI_TARGETS = NO -+GENERATE_LEGEND = YES -+DOT_CLEANUP = YES -+#--------------------------------------------------------------------------- -+# Configuration::additions related to the search engine -+#--------------------------------------------------------------------------- -+SEARCHENGINE = NO -diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.c b/drivers/usb/host/dwc_common_port/dwc_cc.c -new file mode 100644 -index 000000000000..5ec2ae28698c ---- /dev/null -+++ b/drivers/usb/host/dwc_common_port/dwc_cc.c -@@ -0,0 +1,532 @@ -+/* ========================================================================= -+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.c $ -+ * $Revision: #4 $ -+ * $Date: 2010/11/04 $ -+ * $Change: 1621692 $ -+ * -+ * Synopsys Portability Library Software and documentation -+ * (hereinafter, "Software") is an Unsupported proprietary work of -+ * Synopsys, Inc. unless otherwise expressly agreed to in writing -+ * between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product -+ * under any End User Software License Agreement or Agreement for -+ * Licensed Product with Synopsys or any supplement thereto. You are -+ * permitted to use and redistribute this Software in source and binary -+ * forms, with or without modification, provided that redistributions -+ * of source code must retain this notice. You may not view, use, -+ * disclose, copy or distribute this file or any information contained -+ * herein except pursuant to this license grant from Synopsys. If you -+ * do not agree with this notice, including the disclaimer below, then -+ * you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" -+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL -+ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================= */ -+#ifdef DWC_CCLIB -+ -+#include "dwc_cc.h" -+ -+typedef struct dwc_cc -+{ -+ uint32_t uid; -+ uint8_t chid[16]; -+ uint8_t cdid[16]; -+ uint8_t ck[16]; -+ uint8_t *name; -+ uint8_t length; -+ DWC_CIRCLEQ_ENTRY(dwc_cc) list_entry; -+} dwc_cc_t; -+ -+DWC_CIRCLEQ_HEAD(context_list, dwc_cc); -+ -+/** The main structure for CC management. */ -+struct dwc_cc_if -+{ -+ dwc_mutex_t *mutex; -+ char *filename; -+ -+ unsigned is_host:1; -+ -+ dwc_notifier_t *notifier; -+ -+ struct context_list list; -+}; -+ -+#ifdef DEBUG -+static inline void dump_bytes(char *name, uint8_t *bytes, int len) -+{ -+ int i; -+ DWC_PRINTF("%s: ", name); -+ for (i=0; i<len; i++) { -+ DWC_PRINTF("%02x ", bytes[i]); -+ } -+ DWC_PRINTF("\n"); -+} -+#else -+#define dump_bytes(x...) -+#endif -+ -+static dwc_cc_t *alloc_cc(void *mem_ctx, uint8_t *name, uint32_t length) -+{ -+ dwc_cc_t *cc = dwc_alloc(mem_ctx, sizeof(dwc_cc_t)); -+ if (!cc) { -+ return NULL; -+ } -+ DWC_MEMSET(cc, 0, sizeof(dwc_cc_t)); -+ -+ if (name) { -+ cc->length = length; -+ cc->name = dwc_alloc(mem_ctx, length); -+ if (!cc->name) { -+ dwc_free(mem_ctx, cc); -+ return NULL; -+ } -+ -+ DWC_MEMCPY(cc->name, name, length); -+ } -+ -+ return cc; -+} -+ -+static void free_cc(void *mem_ctx, dwc_cc_t *cc) -+{ -+ if (cc->name) { -+ dwc_free(mem_ctx, cc->name); -+ } -+ dwc_free(mem_ctx, cc); -+} -+ -+static uint32_t next_uid(dwc_cc_if_t *cc_if) -+{ -+ uint32_t uid = 0; -+ dwc_cc_t *cc; -+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { -+ if (cc->uid > uid) { -+ uid = cc->uid; -+ } -+ } -+ -+ if (uid == 0) { -+ uid = 255; -+ } -+ -+ return uid + 1; -+} -+ -+static dwc_cc_t *cc_find(dwc_cc_if_t *cc_if, uint32_t uid) -+{ -+ dwc_cc_t *cc; -+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { -+ if (cc->uid == uid) { -+ return cc; -+ } -+ } -+ return NULL; -+} -+ -+static unsigned int cc_data_size(dwc_cc_if_t *cc_if) -+{ -+ unsigned int size = 0; -+ dwc_cc_t *cc; -+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { -+ size += (48 + 1); -+ if (cc->name) { -+ size += cc->length; -+ } -+ } -+ return size; -+} -+ -+static uint32_t cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid) -+{ -+ uint32_t uid = 0; -+ dwc_cc_t *cc; -+ -+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { -+ if (DWC_MEMCMP(cc->chid, chid, 16) == 0) { -+ uid = cc->uid; -+ break; -+ } -+ } -+ return uid; -+} -+static uint32_t cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid) -+{ -+ uint32_t uid = 0; -+ dwc_cc_t *cc; -+ -+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { -+ if (DWC_MEMCMP(cc->cdid, cdid, 16) == 0) { -+ uid = cc->uid; -+ break; -+ } -+ } -+ return uid; -+} -+ -+/* Internal cc_add */ -+static int32_t cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid, -+ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length) -+{ -+ dwc_cc_t *cc; -+ uint32_t uid; -+ -+ if (cc_if->is_host) { -+ uid = cc_match_cdid(cc_if, cdid); -+ } -+ else { -+ uid = cc_match_chid(cc_if, chid); -+ } -+ -+ if (uid) { -+ DWC_DEBUGC("Replacing previous connection context id=%d name=%p name_len=%d", uid, name, length); -+ cc = cc_find(cc_if, uid); -+ } -+ else { -+ cc = alloc_cc(mem_ctx, name, length); -+ cc->uid = next_uid(cc_if); -+ DWC_CIRCLEQ_INSERT_TAIL(&cc_if->list, cc, list_entry); -+ } -+ -+ DWC_MEMCPY(&(cc->chid[0]), chid, 16); -+ DWC_MEMCPY(&(cc->cdid[0]), cdid, 16); -+ DWC_MEMCPY(&(cc->ck[0]), ck, 16); -+ -+ DWC_DEBUGC("Added connection context id=%d name=%p name_len=%d", cc->uid, name, length); -+ dump_bytes("CHID", cc->chid, 16); -+ dump_bytes("CDID", cc->cdid, 16); -+ dump_bytes("CK", cc->ck, 16); -+ return cc->uid; -+} -+ -+/* Internal cc_clear */ -+static void cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if) -+{ -+ while (!DWC_CIRCLEQ_EMPTY(&cc_if->list)) { -+ dwc_cc_t *cc = DWC_CIRCLEQ_FIRST(&cc_if->list); -+ DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry); -+ free_cc(mem_ctx, cc); -+ } -+} -+ -+dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx, -+ dwc_notifier_t *notifier, unsigned is_host) -+{ -+ dwc_cc_if_t *cc_if = NULL; -+ -+ /* Allocate a common_cc_if structure */ -+ cc_if = dwc_alloc(mem_ctx, sizeof(dwc_cc_if_t)); -+ -+ if (!cc_if) -+ return NULL; -+ -+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) -+ DWC_MUTEX_ALLOC_LINUX_DEBUG(cc_if->mutex); -+#else -+ cc_if->mutex = dwc_mutex_alloc(mtx_ctx); -+#endif -+ if (!cc_if->mutex) { -+ dwc_free(mem_ctx, cc_if); -+ return NULL; -+ } -+ -+ DWC_CIRCLEQ_INIT(&cc_if->list); -+ cc_if->is_host = is_host; -+ cc_if->notifier = notifier; -+ return cc_if; -+} -+ -+void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if) -+{ -+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) -+ DWC_MUTEX_FREE(cc_if->mutex); -+#else -+ dwc_mutex_free(mtx_ctx, cc_if->mutex); -+#endif -+ cc_clear(mem_ctx, cc_if); -+ dwc_free(mem_ctx, cc_if); -+} -+ -+static void cc_changed(dwc_cc_if_t *cc_if) -+{ -+ if (cc_if->notifier) { -+ dwc_notify(cc_if->notifier, DWC_CC_LIST_CHANGED_NOTIFICATION, cc_if); -+ } -+} -+ -+void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if) -+{ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ cc_clear(mem_ctx, cc_if); -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ cc_changed(cc_if); -+} -+ -+int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid, -+ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length) -+{ -+ uint32_t uid; -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ uid = cc_add(mem_ctx, cc_if, chid, cdid, ck, name, length); -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ cc_changed(cc_if); -+ -+ return uid; -+} -+ -+void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, uint8_t *chid, -+ uint8_t *cdid, uint8_t *ck, uint8_t *name, uint8_t length) -+{ -+ dwc_cc_t* cc; -+ -+ DWC_DEBUGC("Change connection context %d", id); -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ cc = cc_find(cc_if, id); -+ if (!cc) { -+ DWC_ERROR("Uid %d not found in cc list\n", id); -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ return; -+ } -+ -+ if (chid) { -+ DWC_MEMCPY(&(cc->chid[0]), chid, 16); -+ } -+ if (cdid) { -+ DWC_MEMCPY(&(cc->cdid[0]), cdid, 16); -+ } -+ if (ck) { -+ DWC_MEMCPY(&(cc->ck[0]), ck, 16); -+ } -+ -+ if (name) { -+ if (cc->name) { -+ dwc_free(mem_ctx, cc->name); -+ } -+ cc->name = dwc_alloc(mem_ctx, length); -+ if (!cc->name) { -+ DWC_ERROR("Out of memory in dwc_cc_change()\n"); -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ return; -+ } -+ cc->length = length; -+ DWC_MEMCPY(cc->name, name, length); -+ } -+ -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ -+ cc_changed(cc_if); -+ -+ DWC_DEBUGC("Changed connection context id=%d\n", id); -+ dump_bytes("New CHID", cc->chid, 16); -+ dump_bytes("New CDID", cc->cdid, 16); -+ dump_bytes("New CK", cc->ck, 16); -+} -+ -+void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id) -+{ -+ dwc_cc_t *cc; -+ -+ DWC_DEBUGC("Removing connection context %d", id); -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ cc = cc_find(cc_if, id); -+ if (!cc) { -+ DWC_ERROR("Uid %d not found in cc list\n", id); -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ return; -+ } -+ -+ DWC_CIRCLEQ_REMOVE_INIT(&cc_if->list, cc, list_entry); -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ free_cc(mem_ctx, cc); -+ -+ cc_changed(cc_if); -+} -+ -+uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, unsigned int *length) -+{ -+ uint8_t *buf, *x; -+ uint8_t zero = 0; -+ dwc_cc_t *cc; -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ *length = cc_data_size(cc_if); -+ if (!(*length)) { -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ return NULL; -+ } -+ -+ DWC_DEBUGC("Creating data for saving (length=%d)", *length); -+ -+ buf = dwc_alloc(mem_ctx, *length); -+ if (!buf) { -+ *length = 0; -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ return NULL; -+ } -+ -+ x = buf; -+ DWC_CIRCLEQ_FOREACH(cc, &cc_if->list, list_entry) { -+ DWC_MEMCPY(x, cc->chid, 16); -+ x += 16; -+ DWC_MEMCPY(x, cc->cdid, 16); -+ x += 16; -+ DWC_MEMCPY(x, cc->ck, 16); -+ x += 16; -+ if (cc->name) { -+ DWC_MEMCPY(x, &cc->length, 1); -+ x += 1; -+ DWC_MEMCPY(x, cc->name, cc->length); -+ x += cc->length; -+ } -+ else { -+ DWC_MEMCPY(x, &zero, 1); -+ x += 1; -+ } -+ } -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ -+ return buf; -+} -+ -+void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *data, uint32_t length) -+{ -+ uint8_t name_length; -+ uint8_t *name; -+ uint8_t *chid; -+ uint8_t *cdid; -+ uint8_t *ck; -+ uint32_t i = 0; -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ cc_clear(mem_ctx, cc_if); -+ -+ while (i < length) { -+ chid = &data[i]; -+ i += 16; -+ cdid = &data[i]; -+ i += 16; -+ ck = &data[i]; -+ i += 16; -+ -+ name_length = data[i]; -+ i ++; -+ -+ if (name_length) { -+ name = &data[i]; -+ i += name_length; -+ } -+ else { -+ name = NULL; -+ } -+ -+ /* check to see if we haven't overflown the buffer */ -+ if (i > length) { -+ DWC_ERROR("Data format error while attempting to load CCs " -+ "(nlen=%d, iter=%d, buflen=%d).\n", name_length, i, length); -+ break; -+ } -+ -+ cc_add(mem_ctx, cc_if, chid, cdid, ck, name, name_length); -+ } -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ -+ cc_changed(cc_if); -+} -+ -+uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid) -+{ -+ uint32_t uid = 0; -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ uid = cc_match_chid(cc_if, chid); -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ return uid; -+} -+uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid) -+{ -+ uint32_t uid = 0; -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ uid = cc_match_cdid(cc_if, cdid); -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ return uid; -+} -+ -+uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id) -+{ -+ uint8_t *ck = NULL; -+ dwc_cc_t *cc; -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ cc = cc_find(cc_if, id); -+ if (cc) { -+ ck = cc->ck; -+ } -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ -+ return ck; -+ -+} -+ -+uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id) -+{ -+ uint8_t *retval = NULL; -+ dwc_cc_t *cc; -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ cc = cc_find(cc_if, id); -+ if (cc) { -+ retval = cc->chid; -+ } -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ -+ return retval; -+} -+ -+uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id) -+{ -+ uint8_t *retval = NULL; -+ dwc_cc_t *cc; -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ cc = cc_find(cc_if, id); -+ if (cc) { -+ retval = cc->cdid; -+ } -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ -+ return retval; -+} -+ -+uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length) -+{ -+ uint8_t *retval = NULL; -+ dwc_cc_t *cc; -+ -+ DWC_MUTEX_LOCK(cc_if->mutex); -+ *length = 0; -+ cc = cc_find(cc_if, id); -+ if (cc) { -+ *length = cc->length; -+ retval = cc->name; -+ } -+ DWC_MUTEX_UNLOCK(cc_if->mutex); -+ -+ return retval; -+} -+ -+#endif /* DWC_CCLIB */ -diff --git a/drivers/usb/host/dwc_common_port/dwc_cc.h b/drivers/usb/host/dwc_common_port/dwc_cc.h -new file mode 100644 -index 000000000000..f86e6f21792b ---- /dev/null -+++ b/drivers/usb/host/dwc_common_port/dwc_cc.h -@@ -0,0 +1,224 @@ -+/* ========================================================================= -+ * $File: //dwh/usb_iip/dev/software/dwc_common_port_2/dwc_cc.h $ -+ * $Revision: #4 $ -+ * $Date: 2010/09/28 $ -+ * $Change: 1596182 $ -+ * -+ * Synopsys Portability Library Software and documentation -+ * (hereinafter, "Software") is an Unsupported proprietary work of -+ * Synopsys, Inc. unless otherwise expressly agreed to in writing -+ * between Synopsys and you. -+ * -+ * The Software IS NOT an item of Licensed Software or Licensed Product -+ * under any End User Software License Agreement or Agreement for -+ * Licensed Product with Synopsys or any supplement thereto. You are -+ * permitted to use and redistribute this Software in source and binary -+ * forms, with or without modification, provided that redistributions -+ * of source code must retain this notice. You may not view, use, -+ * disclose, copy or distribute this file or any information contained -+ * herein except pursuant to this license grant from Synopsys. If you -+ * do not agree with this notice, including the disclaimer below, then -+ * you are not authorized to use the Software. -+ * -+ * THIS SOFTWARE IS BEING DISTRIBUTED BY SYNOPSYS SOLELY ON AN "AS IS" -+ * BASIS AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT -+ * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS -+ * FOR A PARTICULAR PURPOSE ARE HEREBY DISCLAIMED. IN NO EVENT SHALL -+ * SYNOPSYS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, -+ * EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, -+ * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR -+ * PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY -+ * OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT -+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE -+ * USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH -+ * DAMAGE. -+ * ========================================================================= */ -+#ifndef _DWC_CC_H_ -+#define _DWC_CC_H_ -+ -+#ifdef __cplusplus -+extern "C" { -+#endif -+ -+/** @file -+ * -+ * This file defines the Context Context library. -+ * -+ * The main data structure is dwc_cc_if_t which is returned by either the -+ * dwc_cc_if_alloc function or returned by the module to the user via a provided -+ * function. The data structure is opaque and should only be manipulated via the -+ * functions provied in this API. -+ * -+ * It manages a list of connection contexts and operations can be performed to -+ * add, remove, query, search, and change, those contexts. Additionally, -+ * a dwc_notifier_t object can be requested from the manager so that -+ * the user can be notified whenever the context list has changed. -+ */ -+ -+#include "dwc_os.h" -+#include "dwc_list.h" -+#include "dwc_notifier.h" -+ -+ -+/* Notifications */ -+#define DWC_CC_LIST_CHANGED_NOTIFICATION "DWC_CC_LIST_CHANGED_NOTIFICATION" -+ -+struct dwc_cc_if; -+typedef struct dwc_cc_if dwc_cc_if_t; -+ -+ -+/** @name Connection Context Operations */ -+/** @{ */ -+ -+/** This function allocates memory for a dwc_cc_if_t structure, initializes -+ * fields to default values, and returns a pointer to the structure or NULL on -+ * error. */ -+extern dwc_cc_if_t *dwc_cc_if_alloc(void *mem_ctx, void *mtx_ctx, -+ dwc_notifier_t *notifier, unsigned is_host); -+ -+/** Frees the memory for the specified CC structure allocated from -+ * dwc_cc_if_alloc(). */ -+extern void dwc_cc_if_free(void *mem_ctx, void *mtx_ctx, dwc_cc_if_t *cc_if); -+ -+/** Removes all contexts from the connection context list */ -+extern void dwc_cc_clear(void *mem_ctx, dwc_cc_if_t *cc_if); -+ -+/** Adds a connection context (CHID, CK, CDID, Name) to the connection context list. -+ * If a CHID already exists, the CK and name are overwritten. Statistics are -+ * not overwritten. -+ * -+ * @param cc_if The cc_if structure. -+ * @param chid A pointer to the 16-byte CHID. This value will be copied. -+ * @param ck A pointer to the 16-byte CK. This value will be copied. -+ * @param cdid A pointer to the 16-byte CDID. This value will be copied. -+ * @param name An optional host friendly name as defined in the association model -+ * spec. Must be a UTF16-LE unicode string. Can be NULL to indicated no name. -+ * @param length The length othe unicode string. -+ * @return A unique identifier used to refer to this context that is valid for -+ * as long as this context is still in the list. */ -+extern int32_t dwc_cc_add(void *mem_ctx, dwc_cc_if_t *cc_if, uint8_t *chid, -+ uint8_t *cdid, uint8_t *ck, uint8_t *name, -+ uint8_t length); -+ -+/** Changes the CHID, CK, CDID, or Name values of a connection context in the -+ * list, preserving any accumulated statistics. This would typically be called -+ * if the host decideds to change the context with a SET_CONNECTION request. -+ * -+ * @param cc_if The cc_if structure. -+ * @param id The identifier of the connection context. -+ * @param chid A pointer to the 16-byte CHID. This value will be copied. NULL -+ * indicates no change. -+ * @param cdid A pointer to the 16-byte CDID. This value will be copied. NULL -+ * indicates no change. -+ * @param ck A pointer to the 16-byte CK. This value will be copied. NULL -+ * indicates no change. -+ * @param name Host friendly name UTF16-LE. NULL indicates no change. -+ * @param length Length of name. */ -+extern void dwc_cc_change(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id, -+ uint8_t *chid, uint8_t *cdid, uint8_t *ck, -+ uint8_t *name, uint8_t length); -+ -+/** Remove the specified connection context. -+ * @param cc_if The cc_if structure. -+ * @param id The identifier of the connection context to remove. */ -+extern void dwc_cc_remove(void *mem_ctx, dwc_cc_if_t *cc_if, int32_t id); -+ -+/** Get a binary block of data for the connection context list and attributes. -+ * This data can be used by the OS specific driver to save the connection -+ * context list into non-volatile memory. -+ * -+ * @param cc_if The cc_if structure. -+ * @param length Return the length of the data buffer. -+ * @return A pointer to the data buffer. The memory for this buffer should be -+ * freed with DWC_FREE() after use. */ -+extern uint8_t *dwc_cc_data_for_save(void *mem_ctx, dwc_cc_if_t *cc_if, -+ unsigned int *length); -+ -+/** Restore the connection context list from the binary data that was previously -+ * returned from a call to dwc_cc_data_for_save. This can be used by the OS specific -+ * driver to load a connection context list from non-volatile memory. -+ * -+ * @param cc_if The cc_if structure. -+ * @param data The data bytes as returned from dwc_cc_data_for_save. -+ * @param length The length of the data. */ -+extern void dwc_cc_restore_from_data(void *mem_ctx, dwc_cc_if_t *cc_if, -+ uint8_t *data, unsigned int length); -+ -+/** Find the connection context from the specified CHID. -+ * -+ * @param cc_if The cc_if structure. -+ * @param chid A pointer to the CHID data. -+ * @return A non-zero identifier of the connection context if the CHID matches. -+ * Otherwise returns 0. */ -+extern uint32_t dwc_cc_match_chid(dwc_cc_if_t *cc_if, uint8_t *chid); -+ -+/** Find the connection context from the specified CDID. -+ * -+ * @param cc_if The cc_if structure. -+ * @param cdid A pointer to the CDID data. -+ * @return A non-zero identifier of the connection context if the CHID matches. -+ * Otherwise returns 0. */ -+extern uint32_t dwc_cc_match_cdid(dwc_cc_if_t *cc_if, uint8_t *cdid); -+ -+/** Retrieve the CK from the specified connection context. -+ * -+ * @param cc_if The cc_if structure. -+ * @param id The identifier of the connection context. -+ * @return A pointer to the CK data. The memory does not need to be freed. */ -+extern uint8_t *dwc_cc_ck(dwc_cc_if_t *cc_if, int32_t id); -+ -+/** Retrieve the CHID from the specified connection context. -+ * -+ * @param cc_if The cc_if structure. -+ * @param id The identifier of the connection context. -+ * @return A pointer to the CHID data. The memory does not need to be freed. */ -+extern uint8_t *dwc_cc_chid(dwc_cc_if_t *cc_if, int32_t id); -+ -+/** Retrieve the CDID from the specified connection context. -+ * -+ * @param cc_if The cc_if structure. -+ * @param id The identifier of the connection context. -+ * @return A pointer to the CDID data. The memory does not need to be freed. */ -+extern uint8_t *dwc_cc_cdid(dwc_cc_if_t *cc_if, int32_t id); -+ -+extern uint8_t *dwc_cc_name(dwc_cc_if_t *cc_if, int32_t id, uint8_t *length); -+ -+/** Checks a buffer for non-zero. -+ * @param id A pointer to a 16 byte buffer. -+ * @return true if the 16 byte value is non-zero. */ -+static inline unsigned dwc_assoc_is_not_zero_id(uint8_t *id) { -+ int i; -+ for (i=0; i<16; i++) { -+ if (id[i]) return 1; -+ } -+ return 0; -+} -+ -+/** Checks a buffer for zero. -+ * @param id A pointer to a 16 byte buffer. -+ * @return true if the 16 byte value is zero. */ -+static inline unsigned dwc_assoc_is_zero_id(uint8_t *id) { -+ return !dwc_assoc_is_not_zero_id(id); -+} -+ -+/** Prints an ASCII representation for the 16-byte chid, cdid, or ck, into -+ * buffer. */ -+static inline int dwc_print_id_string(char *buffer, uint8_t *id) { -+ char *ptr = buffer; -+ int i; -+ for (i=0; i<16; i++) { -+ ptr += DWC_SPRINTF(ptr, "%02x", id[i]); -+ if (i < 15) { -+ ptr += DWC_SPRINTF(ptr, " "); -+ } -+ } -+ return ptr - buffer; -+} -+ -+/** @} */ -+ -+#ifdef __cplusplus -+} -+#endif -+ -+#endif /* _DWC_CC_H_ */ -diff --git a/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c -new file mode 100644 -index 000000000000..6dd04b58f8f6 ---- /dev/null -+++ b/drivers/usb/host/dwc_common_port/dwc_common_fbsd.c -@@ -0,0 +1,1308 @@ -+#include "dwc_os.h" -+#include "dwc_list.h" -+ -+#ifdef DWC_CCLIB -+# include "dwc_cc.h" -+#endif -+ -+#ifdef DWC_CRYPTOLIB -+# include "dwc_modpow.h" -+# include "dwc_dh.h" -+# include "dwc_crypto.h" -+#endif -+ -+#ifdef DWC_NOTIFYLIB -+# include "dwc_notifier.h" -+#endif -+ -+/* OS-Level Implementations */ -+ -+/* This is the FreeBSD 7.0 kernel implementation of the DWC platform library. */ -+ -+ -+/* MISC */ -+ -+void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size) -+{ -+ return memset(dest, byte, size); -+} -+ -+void *DWC_MEMCPY(void *dest, void const *src, uint32_t size) -+{ -+ return memcpy(dest, src, size); -+} -+ -+void *DWC_MEMMOVE(void *dest, void *src, uint32_t size) -+{ -+ bcopy(src, dest, size); -+ return dest; -+} -+ -+int DWC_MEMCMP(void *m1, void *m2, uint32_t size) -+{ -+ return memcmp(m1, m2, size); -+} -+ -+int DWC_STRNCMP(void *s1, void *s2, uint32_t size) -+{ -+ return strncmp(s1, s2, size); -+} -+ -+int DWC_STRCMP(void *s1, void *s2) -+{ -+ return strcmp(s1, s2); -+} -+ -+int DWC_STRLEN(char const *str) -+{ -+ return strlen(str); -+} -+ -+char *DWC_STRCPY(char *to, char const *from) -+{ -+ return strcpy(to, from); -+} -+ -+char *DWC_STRDUP(char const *str) -+{ -+ int len = DWC_STRLEN(str) + 1; -+ char *new = DWC_ALLOC_ATOMIC(len); -+ -+ if (!new) { -+ return NULL; -+ } -+ -+ DWC_MEMCPY(new, str, len); -+ return new; -+} -+ -+int DWC_ATOI(char *str, int32_t *value) -+{ -+ char *end = NULL; -+ -+ *value = strtol(str, &end, 0); -+ if (*end == '\0') { -+ return 0; -+ } -+ -+ return -1; -+} -+ -+int DWC_ATOUI(char *str, uint32_t *value) -+{ -+ char *end = NULL; -+ -+ *value = strtoul(str, &end, 0); -+ if (*end == '\0') { -+ return 0; -+ } -+ -+ return -1; -+} -+ -+ -+#ifdef DWC_UTFLIB -+/* From usbstring.c */ -+ -+int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len) -+{ -+ int count = 0; -+ u8 c; -+ u16 uchar; -+ -+ /* this insists on correct encodings, though not minimal ones. -+ * BUT it currently rejects legit 4-byte UTF-8 code points, -+ * which need surrogate pairs. (Unicode 3.1 can use them.) -+ */ -+ while (len != 0 && (c = (u8) *s++) != 0) { -+ if (unlikely(c & 0x80)) { -+ // 2-byte sequence: -+ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx -+ if ((c & 0xe0) == 0xc0) { -+ uchar = (c & 0x1f) << 6; -+ -+ c = (u8) *s++; -+ if ((c & 0xc0) != 0xc0) -+ goto fail; -+ c &= 0x3f; -+ uchar |= c; -+ -+ // 3-byte sequence (most CJKV characters): -+ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx -+ } else if ((c & 0xf0) == 0xe0) { -+ uchar = (c & 0x0f) << 12; -+ -+ c = (u8) *s++; -+ if ((c & 0xc0) != 0xc0) -+ goto fail; -+ c &= 0x3f; -+ uchar |= c << 6; -+ -+ c = (u8) *s++; -+ if ((c & 0xc0) != 0xc0) -+ goto fail; -+ c &= 0x3f; -+ uchar |= c; -+ -+ /* no bogus surrogates */ -+ if (0xd800 <= uchar && uchar <= 0xdfff) -+ goto fail; -+ -+ // 4-byte sequence (surrogate pairs, currently rare): -+ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx -+ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx -+ // (uuuuu = wwww + 1) -+ // FIXME accept the surrogate code points (only) -+ } else -+ goto fail; -+ } else -+ uchar = c; -+ put_unaligned (cpu_to_le16 (uchar), cp++); -+ count++; -+ len--; -+ } -+ return count; -+fail: -+ return -1; -+} -+ -+#endif /* DWC_UTFLIB */ -+ -+ -+/* dwc_debug.h */ -+ -+dwc_bool_t DWC_IN_IRQ(void) -+{ -+// return in_irq(); -+ return 0; -+} -+ -+dwc_bool_t DWC_IN_BH(void) -+{ -+// return in_softirq(); -+ return 0; -+} -+ -+void DWC_VPRINTF(char *format, va_list args) -+{ -+ vprintf(format, args); -+} -+ -+int DWC_VSNPRINTF(char *str, int size, char *format, va_list args) -+{ -+ return vsnprintf(str, size, format, args); -+} -+ -+void DWC_PRINTF(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+ -+int DWC_SPRINTF(char *buffer, char *format, ...) -+{ -+ int retval; -+ va_list args; -+ -+ va_start(args, format); -+ retval = vsprintf(buffer, format, args); -+ va_end(args); -+ return retval; -+} -+ -+int DWC_SNPRINTF(char *buffer, int size, char *format, ...) -+{ -+ int retval; -+ va_list args; -+ -+ va_start(args, format); -+ retval = vsnprintf(buffer, size, format, args); -+ va_end(args); -+ return retval; -+} -+ -+void __DWC_WARN(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+ -+void __DWC_ERROR(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+ -+void DWC_EXCEPTION(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+// BUG_ON(1); ??? -+} -+ -+#ifdef DEBUG -+void __DWC_DEBUG(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+#endif -+ -+ -+/* dwc_mem.h */ -+ -+#if 0 -+dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, -+ uint32_t align, -+ uint32_t alloc) -+{ -+ struct dma_pool *pool = dma_pool_create("Pool", NULL, -+ size, align, alloc); -+ return (dwc_pool_t *)pool; -+} -+ -+void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool) -+{ -+ dma_pool_destroy((struct dma_pool *)pool); -+} -+ -+void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr) -+{ -+// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr); -+ return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr); -+} -+ -+void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr) -+{ -+ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr); -+ memset(..); -+} -+ -+void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr) -+{ -+ dma_pool_free(pool, vaddr, daddr); -+} -+#endif -+ -+static void dmamap_cb(void *arg, bus_dma_segment_t *segs, int nseg, int error) -+{ -+ if (error) -+ return; -+ *(bus_addr_t *)arg = segs[0].ds_addr; -+} -+ -+void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr) -+{ -+ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx; -+ int error; -+ -+ error = bus_dma_tag_create( -+#if __FreeBSD_version >= 700000 -+ bus_get_dma_tag(dma->dev), /* parent */ -+#else -+ NULL, /* parent */ -+#endif -+ 4, 0, /* alignment, bounds */ -+ BUS_SPACE_MAXADDR_32BIT, /* lowaddr */ -+ BUS_SPACE_MAXADDR, /* highaddr */ -+ NULL, NULL, /* filter, filterarg */ -+ size, /* maxsize */ -+ 1, /* nsegments */ -+ size, /* maxsegsize */ -+ 0, /* flags */ -+ NULL, /* lockfunc */ -+ NULL, /* lockarg */ -+ &dma->dma_tag); -+ if (error) { -+ device_printf(dma->dev, "%s: bus_dma_tag_create failed: %d\n", -+ __func__, error); -+ goto fail_0; -+ } -+ -+ error = bus_dmamem_alloc(dma->dma_tag, &dma->dma_vaddr, -+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT, &dma->dma_map); -+ if (error) { -+ device_printf(dma->dev, "%s: bus_dmamem_alloc(%ju) failed: %d\n", -+ __func__, (uintmax_t)size, error); -+ goto fail_1; -+ } -+ -+ dma->dma_paddr = 0; -+ error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, size, -+ dmamap_cb, &dma->dma_paddr, BUS_DMA_NOWAIT); -+ if (error || dma->dma_paddr == 0) { -+ device_printf(dma->dev, "%s: bus_dmamap_load failed: %d\n", -+ __func__, error); -+ goto fail_2; -+ } -+ -+ *dma_addr = dma->dma_paddr; -+ return dma->dma_vaddr; -+ -+fail_2: -+ bus_dmamap_unload(dma->dma_tag, dma->dma_map); -+fail_1: -+ bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); -+ bus_dma_tag_destroy(dma->dma_tag); -+fail_0: -+ dma->dma_map = NULL; -+ dma->dma_tag = NULL; -+ -+ return NULL; -+} -+ -+void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr) -+{ -+ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx; -+ -+ if (dma->dma_tag == NULL) -+ return; -+ if (dma->dma_map != NULL) { -+ bus_dmamap_sync(dma->dma_tag, dma->dma_map, -+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); -+ bus_dmamap_unload(dma->dma_tag, dma->dma_map); -+ bus_dmamem_free(dma->dma_tag, dma->dma_vaddr, dma->dma_map); -+ dma->dma_map = NULL; -+ } -+ -+ bus_dma_tag_destroy(dma->dma_tag); -+ dma->dma_tag = NULL; -+} -+ -+void *__DWC_ALLOC(void *mem_ctx, uint32_t size) -+{ -+ return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO); -+} -+ -+void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size) -+{ -+ return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); -+} -+ -+void __DWC_FREE(void *mem_ctx, void *addr) -+{ -+ free(addr, M_DEVBUF); -+} -+ -+ -+#ifdef DWC_CRYPTOLIB -+/* dwc_crypto.h */ -+ -+void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length) -+{ -+ get_random_bytes(buffer, length); -+} -+ -+int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out) -+{ -+ struct crypto_blkcipher *tfm; -+ struct blkcipher_desc desc; -+ struct scatterlist sgd; -+ struct scatterlist sgs; -+ -+ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); -+ if (tfm == NULL) { -+ printk("failed to load transform for aes CBC\n"); -+ return -1; -+ } -+ -+ crypto_blkcipher_setkey(tfm, key, keylen); -+ crypto_blkcipher_set_iv(tfm, iv, 16); -+ -+ sg_init_one(&sgd, out, messagelen); -+ sg_init_one(&sgs, message, messagelen); -+ -+ desc.tfm = tfm; -+ desc.flags = 0; -+ -+ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) { -+ crypto_free_blkcipher(tfm); -+ DWC_ERROR("AES CBC encryption failed"); -+ return -1; -+ } -+ -+ crypto_free_blkcipher(tfm); -+ return 0; -+} -+ -+int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out) -+{ -+ struct crypto_hash *tfm; -+ struct hash_desc desc; -+ struct scatterlist sg; -+ -+ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); -+ if (IS_ERR(tfm)) { -+ DWC_ERROR("Failed to load transform for sha256: %ld", PTR_ERR(tfm)); -+ return 0; -+ } -+ desc.tfm = tfm; -+ desc.flags = 0; -+ -+ sg_init_one(&sg, message, len); -+ crypto_hash_digest(&desc, &sg, len, out); -+ crypto_free_hash(tfm); -+ -+ return 1; -+} -+ -+int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, -+ uint8_t *key, uint32_t keylen, uint8_t *out) -+{ -+ struct crypto_hash *tfm; -+ struct hash_desc desc; -+ struct scatterlist sg; -+ -+ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC); -+ if (IS_ERR(tfm)) { -+ DWC_ERROR("Failed to load transform for hmac(sha256): %ld", PTR_ERR(tfm)); -+ return 0; -+ } -+ desc.tfm = tfm; -+ desc.flags = 0; -+ -+ sg_init_one(&sg, message, messagelen); -+ crypto_hash_setkey(tfm, key, keylen); -+ crypto_hash_digest(&desc, &sg, messagelen, out); -+ crypto_free_hash(tfm); -+ -+ return 1; -+} -+ -+#endif /* DWC_CRYPTOLIB */ -+ -+ -+/* Byte Ordering Conversions */ -+ -+uint32_t DWC_CPU_TO_LE32(uint32_t *p) -+{ -+#ifdef __LITTLE_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ -+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); -+#endif -+} -+ -+uint32_t DWC_CPU_TO_BE32(uint32_t *p) -+{ -+#ifdef __BIG_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ -+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); -+#endif -+} -+ -+uint32_t DWC_LE32_TO_CPU(uint32_t *p) -+{ -+#ifdef __LITTLE_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ -+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); -+#endif -+} -+ -+uint32_t DWC_BE32_TO_CPU(uint32_t *p) -+{ -+#ifdef __BIG_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ -+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); -+#endif -+} -+ -+uint16_t DWC_CPU_TO_LE16(uint16_t *p) -+{ -+#ifdef __LITTLE_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ return (u_p[1] | (u_p[0] << 8)); -+#endif -+} -+ -+uint16_t DWC_CPU_TO_BE16(uint16_t *p) -+{ -+#ifdef __BIG_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ return (u_p[1] | (u_p[0] << 8)); -+#endif -+} -+ -+uint16_t DWC_LE16_TO_CPU(uint16_t *p) -+{ -+#ifdef __LITTLE_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ return (u_p[1] | (u_p[0] << 8)); -+#endif -+} -+ -+uint16_t DWC_BE16_TO_CPU(uint16_t *p) -+{ -+#ifdef __BIG_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ return (u_p[1] | (u_p[0] << 8)); -+#endif -+} -+ -+ -+/* Registers */ -+ -+uint32_t DWC_READ_REG32(void *io_ctx, uint32_t volatile *reg) -+{ -+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx; -+ bus_size_t ior = (bus_size_t)reg; -+ -+ return bus_space_read_4(io->iot, io->ioh, ior); -+} -+ -+#if 0 -+uint64_t DWC_READ_REG64(void *io_ctx, uint64_t volatile *reg) -+{ -+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx; -+ bus_size_t ior = (bus_size_t)reg; -+ -+ return bus_space_read_8(io->iot, io->ioh, ior); -+} -+#endif -+ -+void DWC_WRITE_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t value) -+{ -+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx; -+ bus_size_t ior = (bus_size_t)reg; -+ -+ bus_space_write_4(io->iot, io->ioh, ior, value); -+} -+ -+#if 0 -+void DWC_WRITE_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t value) -+{ -+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx; -+ bus_size_t ior = (bus_size_t)reg; -+ -+ bus_space_write_8(io->iot, io->ioh, ior, value); -+} -+#endif -+ -+void DWC_MODIFY_REG32(void *io_ctx, uint32_t volatile *reg, uint32_t clear_mask, -+ uint32_t set_mask) -+{ -+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx; -+ bus_size_t ior = (bus_size_t)reg; -+ -+ bus_space_write_4(io->iot, io->ioh, ior, -+ (bus_space_read_4(io->iot, io->ioh, ior) & -+ ~clear_mask) | set_mask); -+} -+ -+#if 0 -+void DWC_MODIFY_REG64(void *io_ctx, uint64_t volatile *reg, uint64_t clear_mask, -+ uint64_t set_mask) -+{ -+ dwc_ioctx_t *io = (dwc_ioctx_t *)io_ctx; -+ bus_size_t ior = (bus_size_t)reg; -+ -+ bus_space_write_8(io->iot, io->ioh, ior, -+ (bus_space_read_8(io->iot, io->ioh, ior) & -+ ~clear_mask) | set_mask); -+} -+#endif -+ -+ -+/* Locking */ -+ -+dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void) -+{ -+ struct mtx *sl = DWC_ALLOC(sizeof(*sl)); -+ -+ if (!sl) { -+ DWC_ERROR("Cannot allocate memory for spinlock"); -+ return NULL; -+ } -+ -+ mtx_init(sl, "dw3spn", NULL, MTX_SPIN); -+ return (dwc_spinlock_t *)sl; -+} -+ -+void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock) -+{ -+ struct mtx *sl = (struct mtx *)lock; -+ -+ mtx_destroy(sl); -+ DWC_FREE(sl); -+} -+ -+void DWC_SPINLOCK(dwc_spinlock_t *lock) -+{ -+ mtx_lock_spin((struct mtx *)lock); // ??? -+} -+ -+void DWC_SPINUNLOCK(dwc_spinlock_t *lock) -+{ -+ mtx_unlock_spin((struct mtx *)lock); // ??? -+} -+ -+void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags) -+{ -+ mtx_lock_spin((struct mtx *)lock); -+} -+ -+void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags) -+{ -+ mtx_unlock_spin((struct mtx *)lock); -+} -+ -+dwc_mutex_t *DWC_MUTEX_ALLOC(void) -+{ -+ struct mtx *m; -+ dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mtx)); -+ -+ if (!mutex) { -+ DWC_ERROR("Cannot allocate memory for mutex"); -+ return NULL; -+ } -+ -+ m = (struct mtx *)mutex; -+ mtx_init(m, "dw3mtx", NULL, MTX_DEF); -+ return mutex; -+} -+ -+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) -+#else -+void DWC_MUTEX_FREE(dwc_mutex_t *mutex) -+{ -+ mtx_destroy((struct mtx *)mutex); -+ DWC_FREE(mutex); -+} -+#endif -+ -+void DWC_MUTEX_LOCK(dwc_mutex_t *mutex) -+{ -+ struct mtx *m = (struct mtx *)mutex; -+ -+ mtx_lock(m); -+} -+ -+int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex) -+{ -+ struct mtx *m = (struct mtx *)mutex; -+ -+ return mtx_trylock(m); -+} -+ -+void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex) -+{ -+ struct mtx *m = (struct mtx *)mutex; -+ -+ mtx_unlock(m); -+} -+ -+ -+/* Timing */ -+ -+void DWC_UDELAY(uint32_t usecs) -+{ -+ DELAY(usecs); -+} -+ -+void DWC_MDELAY(uint32_t msecs) -+{ -+ do { -+ DELAY(1000); -+ } while (--msecs); -+} -+ -+void DWC_MSLEEP(uint32_t msecs) -+{ -+ struct timeval tv; -+ -+ tv.tv_sec = msecs / 1000; -+ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000; -+ pause("dw3slp", tvtohz(&tv)); -+} -+ -+uint32_t DWC_TIME(void) -+{ -+ struct timeval tv; -+ -+ microuptime(&tv); // or getmicrouptime? (less precise, but faster) -+ return tv.tv_sec * 1000 + tv.tv_usec / 1000; -+} -+ -+ -+/* Timers */ -+ -+struct dwc_timer { -+ struct callout t; -+ char *name; -+ dwc_spinlock_t *lock; -+ dwc_timer_callback_t cb; -+ void *data; -+}; -+ -+dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data) -+{ -+ dwc_timer_t *t = DWC_ALLOC(sizeof(*t)); -+ -+ if (!t) { -+ DWC_ERROR("Cannot allocate memory for timer"); -+ return NULL; -+ } -+ -+ callout_init(&t->t, 1); -+ -+ t->name = DWC_STRDUP(name); -+ if (!t->name) { -+ DWC_ERROR("Cannot allocate memory for timer->name"); -+ goto no_name; -+ } -+ -+ t->lock = DWC_SPINLOCK_ALLOC(); -+ if (!t->lock) { -+ DWC_ERROR("Cannot allocate memory for lock"); -+ goto no_lock; -+ } -+ -+ t->cb = cb; -+ t->data = data; -+ -+ return t; -+ -+ no_lock: -+ DWC_FREE(t->name); -+ no_name: -+ DWC_FREE(t); -+ -+ return NULL; -+} -+ -+void DWC_TIMER_FREE(dwc_timer_t *timer) -+{ -+ callout_stop(&timer->t); -+ DWC_SPINLOCK_FREE(timer->lock); -+ DWC_FREE(timer->name); -+ DWC_FREE(timer); -+} -+ -+void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time) -+{ -+ struct timeval tv; -+ -+ tv.tv_sec = time / 1000; -+ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000; -+ callout_reset(&timer->t, tvtohz(&tv), timer->cb, timer->data); -+} -+ -+void DWC_TIMER_CANCEL(dwc_timer_t *timer) -+{ -+ callout_stop(&timer->t); -+} -+ -+ -+/* Wait Queues */ -+ -+struct dwc_waitq { -+ struct mtx lock; -+ int abort; -+}; -+ -+dwc_waitq_t *DWC_WAITQ_ALLOC(void) -+{ -+ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq)); -+ -+ if (!wq) { -+ DWC_ERROR("Cannot allocate memory for waitqueue"); -+ return NULL; -+ } -+ -+ mtx_init(&wq->lock, "dw3wtq", NULL, MTX_DEF); -+ wq->abort = 0; -+ -+ return wq; -+} -+ -+void DWC_WAITQ_FREE(dwc_waitq_t *wq) -+{ -+ mtx_destroy(&wq->lock); -+ DWC_FREE(wq); -+} -+ -+int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data) -+{ -+// intrmask_t ipl; -+ int result = 0; -+ -+ mtx_lock(&wq->lock); -+// ipl = splbio(); -+ -+ /* Skip the sleep if already aborted or triggered */ -+ if (!wq->abort && !cond(data)) { -+// splx(ipl); -+ result = msleep(wq, &wq->lock, PCATCH, "dw3wat", 0); // infinite timeout -+// ipl = splbio(); -+ } -+ -+ if (result == ERESTART) { // signaled - restart -+ result = -DWC_E_RESTART; -+ -+ } else if (result == EINTR) { // signaled - interrupt -+ result = -DWC_E_ABORT; -+ -+ } else if (wq->abort) { -+ result = -DWC_E_ABORT; -+ -+ } else { -+ result = 0; -+ } -+ -+ wq->abort = 0; -+// splx(ipl); -+ mtx_unlock(&wq->lock); -+ return result; -+} -+ -+int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, -+ void *data, int32_t msecs) -+{ -+ struct timeval tv, tv1, tv2; -+// intrmask_t ipl; -+ int result = 0; -+ -+ tv.tv_sec = msecs / 1000; -+ tv.tv_usec = (msecs - tv.tv_sec * 1000) * 1000; -+ -+ mtx_lock(&wq->lock); -+// ipl = splbio(); -+ -+ /* Skip the sleep if already aborted or triggered */ -+ if (!wq->abort && !cond(data)) { -+// splx(ipl); -+ getmicrouptime(&tv1); -+ result = msleep(wq, &wq->lock, PCATCH, "dw3wto", tvtohz(&tv)); -+ getmicrouptime(&tv2); -+// ipl = splbio(); -+ } -+ -+ if (result == 0) { // awoken -+ if (wq->abort) { -+ result = -DWC_E_ABORT; -+ } else { -+ tv2.tv_usec -= tv1.tv_usec; -+ if (tv2.tv_usec < 0) { -+ tv2.tv_usec += 1000000; -+ tv2.tv_sec--; -+ } -+ -+ tv2.tv_sec -= tv1.tv_sec; -+ result = tv2.tv_sec * 1000 + tv2.tv_usec / 1000; -+ result = msecs - result; -+ if (result <= 0) -+ result = 1; -+ } -+ } else if (result == ERESTART) { // signaled - restart -+ result = -DWC_E_RESTART; -+ -+ } else if (result == EINTR) { // signaled - interrupt -+ result = -DWC_E_ABORT; -+ -+ } else { // timed out -+ result = -DWC_E_TIMEOUT; -+ } -+ -+ wq->abort = 0; -+// splx(ipl); -+ mtx_unlock(&wq->lock); -+ return result; -+} -+ -+void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq) -+{ -+ wakeup(wq); -+} -+ -+void DWC_WAITQ_ABORT(dwc_waitq_t *wq) -+{ -+// intrmask_t ipl; -+ -+ mtx_lock(&wq->lock); -+// ipl = splbio(); -+ wq->abort = 1; -+ wakeup(wq); -+// splx(ipl); -+ mtx_unlock(&wq->lock); -+} -+ -+ -+/* Threading */ -+ -+struct dwc_thread { -+ struct proc *proc; -+ int abort; -+}; -+ -+dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data) -+{ -+ int retval; -+ dwc_thread_t *thread = DWC_ALLOC(sizeof(*thread)); -+ -+ if (!thread) { -+ return NULL; -+ } -+ -+ thread->abort = 0; -+ retval = kthread_create((void (*)(void *))func, data, &thread->proc, -+ RFPROC | RFNOWAIT, 0, "%s", name); -+ if (retval) { -+ DWC_FREE(thread); -+ return NULL; -+ } -+ -+ return thread; -+} -+ -+int DWC_THREAD_STOP(dwc_thread_t *thread) -+{ -+ int retval; -+ -+ thread->abort = 1; -+ retval = tsleep(&thread->abort, 0, "dw3stp", 60 * hz); -+ -+ if (retval == 0) { -+ /* DWC_THREAD_EXIT() will free the thread struct */ -+ return 0; -+ } -+ -+ /* NOTE: We leak the thread struct if thread doesn't die */ -+ -+ if (retval == EWOULDBLOCK) { -+ return -DWC_E_TIMEOUT; -+ } -+ -+ return -DWC_E_UNKNOWN; -+} -+ -+dwc_bool_t DWC_THREAD_SHOULD_STOP(dwc_thread_t *thread) -+{ -+ return thread->abort; -+} -+ -+void DWC_THREAD_EXIT(dwc_thread_t *thread) -+{ -+ wakeup(&thread->abort); -+ DWC_FREE(thread); -+ kthread_exit(0); -+} -+ -+ -+/* tasklets -+ - Runs in interrupt context (cannot sleep) -+ - Each tasklet runs on a single CPU [ How can we ensure this on FreeBSD? Does it matter? ] -+ - Different tasklets can be running simultaneously on different CPUs [ shouldn't matter ] -+ */ -+struct dwc_tasklet { -+ struct task t; -+ dwc_tasklet_callback_t cb; -+ void *data; -+}; -+ -+static void tasklet_callback(void *data, int pending) // what to do with pending ??? -+{ -+ dwc_tasklet_t *task = (dwc_tasklet_t *)data; -+ -+ task->cb(task->data); -+} -+ -+dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data) -+{ -+ dwc_tasklet_t *task = DWC_ALLOC(sizeof(*task)); -+ -+ if (task) { -+ task->cb = cb; -+ task->data = data; -+ TASK_INIT(&task->t, 0, tasklet_callback, task); -+ } else { -+ DWC_ERROR("Cannot allocate memory for tasklet"); -+ } -+ -+ return task; -+} -+ -+void DWC_TASK_FREE(dwc_tasklet_t *task) -+{ -+ taskqueue_drain(taskqueue_fast, &task->t); // ??? -+ DWC_FREE(task); -+} -+ -+void DWC_TASK_SCHEDULE(dwc_tasklet_t *task) -+{ -+ /* Uses predefined system queue */ -+ taskqueue_enqueue_fast(taskqueue_fast, &task->t); -+} -+ -+ -+/* workqueues -+ - Runs in process context (can sleep) -+ */ -+typedef struct work_container { -+ dwc_work_callback_t cb; -+ void *data; -+ dwc_workq_t *wq; -+ char *name; -+ int hz; -+ -+#ifdef DEBUG -+ DWC_CIRCLEQ_ENTRY(work_container) entry; -+#endif -+ struct task task; -+} work_container_t; -+ -+#ifdef DEBUG -+DWC_CIRCLEQ_HEAD(work_container_queue, work_container); -+#endif -+ -+struct dwc_workq { -+ struct taskqueue *taskq; -+ dwc_spinlock_t *lock; -+ dwc_waitq_t *waitq; -+ int pending; -+ -+#ifdef DEBUG -+ struct work_container_queue entries; -+#endif -+}; -+ -+static void do_work(void *data, int pending) // what to do with pending ??? -+{ -+ work_container_t *container = (work_container_t *)data; -+ dwc_workq_t *wq = container->wq; -+ dwc_irqflags_t flags; -+ -+ if (container->hz) { -+ pause("dw3wrk", container->hz); -+ } -+ -+ container->cb(container->data); -+ DWC_DEBUG("Work done: %s, container=%p", container->name, container); -+ -+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags); -+ -+#ifdef DEBUG -+ DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry); -+#endif -+ if (container->name) -+ DWC_FREE(container->name); -+ DWC_FREE(container); -+ wq->pending--; -+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags); -+ DWC_WAITQ_TRIGGER(wq->waitq); -+} -+ -+static int work_done(void *data) -+{ -+ dwc_workq_t *workq = (dwc_workq_t *)data; -+ -+ return workq->pending == 0; -+} -+ -+int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout) -+{ -+ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout); -+} -+ -+dwc_workq_t *DWC_WORKQ_ALLOC(char *name) -+{ -+ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq)); -+ -+ if (!wq) { -+ DWC_ERROR("Cannot allocate memory for workqueue"); -+ return NULL; -+ } -+ -+ wq->taskq = taskqueue_create(name, M_NOWAIT, taskqueue_thread_enqueue, &wq->taskq); -+ if (!wq->taskq) { -+ DWC_ERROR("Cannot allocate memory for taskqueue"); -+ goto no_taskq; -+ } -+ -+ wq->pending = 0; -+ -+ wq->lock = DWC_SPINLOCK_ALLOC(); -+ if (!wq->lock) { -+ DWC_ERROR("Cannot allocate memory for spinlock"); -+ goto no_lock; -+ } -+ -+ wq->waitq = DWC_WAITQ_ALLOC(); -+ if (!wq->waitq) { -+ DWC_ERROR("Cannot allocate memory for waitqueue"); -+ goto no_waitq; -+ } -+ -+ taskqueue_start_threads(&wq->taskq, 1, PWAIT, "%s taskq", "dw3tsk"); -+ -+#ifdef DEBUG -+ DWC_CIRCLEQ_INIT(&wq->entries); -+#endif -+ return wq; -+ -+ no_waitq: -+ DWC_SPINLOCK_FREE(wq->lock); -+ no_lock: -+ taskqueue_free(wq->taskq); -+ no_taskq: -+ DWC_FREE(wq); -+ -+ return NULL; -+} -+ -+void DWC_WORKQ_FREE(dwc_workq_t *wq) -+{ -+#ifdef DEBUG -+ dwc_irqflags_t flags; -+ -+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags); -+ -+ if (wq->pending != 0) { -+ struct work_container *container; -+ -+ DWC_ERROR("Destroying work queue with pending work"); -+ -+ DWC_CIRCLEQ_FOREACH(container, &wq->entries, entry) { -+ DWC_ERROR("Work %s still pending", container->name); -+ } -+ } -+ -+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags); -+#endif -+ DWC_WAITQ_FREE(wq->waitq); -+ DWC_SPINLOCK_FREE(wq->lock); -+ taskqueue_free(wq->taskq); -+ DWC_FREE(wq); -+} -+ -+void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data, -+ char *format, ...) -+{ -+ dwc_irqflags_t flags; -+ work_container_t *container; -+ static char name[128]; -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VSNPRINTF(name, 128, format, args); -+ va_end(args); -+ -+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags); -+ wq->pending++; -+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags); -+ DWC_WAITQ_TRIGGER(wq->waitq); -+ -+ container = DWC_ALLOC_ATOMIC(sizeof(*container)); -+ if (!container) { -+ DWC_ERROR("Cannot allocate memory for container"); -+ return; -+ } -+ -+ container->name = DWC_STRDUP(name); -+ if (!container->name) { -+ DWC_ERROR("Cannot allocate memory for container->name"); -+ DWC_FREE(container); -+ return; -+ } -+ -+ container->cb = cb; -+ container->data = data; -+ container->wq = wq; -+ container->hz = 0; -+ -+ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container); -+ -+ TASK_INIT(&container->task, 0, do_work, container); -+ -+#ifdef DEBUG -+ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry); -+#endif -+ taskqueue_enqueue_fast(wq->taskq, &container->task); -+} -+ -+void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb, -+ void *data, uint32_t time, char *format, ...) -+{ -+ dwc_irqflags_t flags; -+ work_container_t *container; -+ static char name[128]; -+ struct timeval tv; -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VSNPRINTF(name, 128, format, args); -+ va_end(args); -+ -+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags); -+ wq->pending++; -+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags); -+ DWC_WAITQ_TRIGGER(wq->waitq); -+ -+ container = DWC_ALLOC_ATOMIC(sizeof(*container)); -+ if (!container) { -+ DWC_ERROR("Cannot allocate memory for container"); -+ return; -+ } -+ -+ container->name = DWC_STRDUP(name); -+ if (!container->name) { -+ DWC_ERROR("Cannot allocate memory for container->name"); -+ DWC_FREE(container); -+ return; -+ } -+ -+ container->cb = cb; -+ container->data = data; -+ container->wq = wq; -+ -+ tv.tv_sec = time / 1000; -+ tv.tv_usec = (time - tv.tv_sec * 1000) * 1000; -+ container->hz = tvtohz(&tv); -+ -+ DWC_DEBUG("Queueing work: %s, container=%p", container->name, container); -+ -+ TASK_INIT(&container->task, 0, do_work, container); -+ -+#ifdef DEBUG -+ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry); -+#endif -+ taskqueue_enqueue_fast(wq->taskq, &container->task); -+} -+ -+int DWC_WORKQ_PENDING(dwc_workq_t *wq) -+{ -+ return wq->pending; -+} -diff --git a/drivers/usb/host/dwc_common_port/dwc_common_linux.c b/drivers/usb/host/dwc_common_port/dwc_common_linux.c -new file mode 100644 -index 000000000000..1460afaf997d ---- /dev/null -+++ b/drivers/usb/host/dwc_common_port/dwc_common_linux.c -@@ -0,0 +1,1409 @@ -+#include <linux/kernel.h> -+#include <linux/init.h> -+#include <linux/module.h> -+#include <linux/kthread.h> -+ -+#ifdef DWC_CCLIB -+# include "dwc_cc.h" -+#endif -+ -+#ifdef DWC_CRYPTOLIB -+# include "dwc_modpow.h" -+# include "dwc_dh.h" -+# include "dwc_crypto.h" -+#endif -+ -+#ifdef DWC_NOTIFYLIB -+# include "dwc_notifier.h" -+#endif -+ -+/* OS-Level Implementations */ -+ -+/* This is the Linux kernel implementation of the DWC platform library. */ -+#include <linux/moduleparam.h> -+#include <linux/ctype.h> -+#include <linux/crypto.h> -+#include <linux/delay.h> -+#include <linux/device.h> -+#include <linux/dma-mapping.h> -+#include <linux/cdev.h> -+#include <linux/errno.h> -+#include <linux/interrupt.h> -+#include <linux/jiffies.h> -+#include <linux/list.h> -+#include <linux/pci.h> -+#include <linux/random.h> -+#include <linux/scatterlist.h> -+#include <linux/slab.h> -+#include <linux/stat.h> -+#include <linux/string.h> -+#include <linux/timer.h> -+#include <linux/usb.h> -+ -+#include <linux/version.h> -+ -+#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24) -+# include <linux/usb/gadget.h> -+#else -+# include <linux/usb_gadget.h> -+#endif -+ -+#include <asm/io.h> -+#include <asm/page.h> -+#include <asm/uaccess.h> -+#include <asm/unaligned.h> -+ -+#include "dwc_os.h" -+#include "dwc_list.h" -+ -+ -+/* MISC */ -+ -+void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size) -+{ -+ return memset(dest, byte, size); -+} -+ -+void *DWC_MEMCPY(void *dest, void const *src, uint32_t size) -+{ -+ return memcpy(dest, src, size); -+} -+ -+void *DWC_MEMMOVE(void *dest, void *src, uint32_t size) -+{ -+ return memmove(dest, src, size); -+} -+ -+int DWC_MEMCMP(void *m1, void *m2, uint32_t size) -+{ -+ return memcmp(m1, m2, size); -+} -+ -+int DWC_STRNCMP(void *s1, void *s2, uint32_t size) -+{ -+ return strncmp(s1, s2, size); -+} -+ -+int DWC_STRCMP(void *s1, void *s2) -+{ -+ return strcmp(s1, s2); -+} -+ -+int DWC_STRLEN(char const *str) -+{ -+ return strlen(str); -+} -+ -+char *DWC_STRCPY(char *to, char const *from) -+{ -+ return strcpy(to, from); -+} -+ -+char *DWC_STRDUP(char const *str) -+{ -+ int len = DWC_STRLEN(str) + 1; -+ char *new = DWC_ALLOC_ATOMIC(len); -+ -+ if (!new) { -+ return NULL; -+ } -+ -+ DWC_MEMCPY(new, str, len); -+ return new; -+} -+ -+int DWC_ATOI(const char *str, int32_t *value) -+{ -+ char *end = NULL; -+ -+ *value = simple_strtol(str, &end, 0); -+ if (*end == '\0') { -+ return 0; -+ } -+ -+ return -1; -+} -+ -+int DWC_ATOUI(const char *str, uint32_t *value) -+{ -+ char *end = NULL; -+ -+ *value = simple_strtoul(str, &end, 0); -+ if (*end == '\0') { -+ return 0; -+ } -+ -+ return -1; -+} -+ -+ -+#ifdef DWC_UTFLIB -+/* From usbstring.c */ -+ -+int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len) -+{ -+ int count = 0; -+ u8 c; -+ u16 uchar; -+ -+ /* this insists on correct encodings, though not minimal ones. -+ * BUT it currently rejects legit 4-byte UTF-8 code points, -+ * which need surrogate pairs. (Unicode 3.1 can use them.) -+ */ -+ while (len != 0 && (c = (u8) *s++) != 0) { -+ if (unlikely(c & 0x80)) { -+ // 2-byte sequence: -+ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx -+ if ((c & 0xe0) == 0xc0) { -+ uchar = (c & 0x1f) << 6; -+ -+ c = (u8) *s++; -+ if ((c & 0xc0) != 0xc0) -+ goto fail; -+ c &= 0x3f; -+ uchar |= c; -+ -+ // 3-byte sequence (most CJKV characters): -+ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx -+ } else if ((c & 0xf0) == 0xe0) { -+ uchar = (c & 0x0f) << 12; -+ -+ c = (u8) *s++; -+ if ((c & 0xc0) != 0xc0) -+ goto fail; -+ c &= 0x3f; -+ uchar |= c << 6; -+ -+ c = (u8) *s++; -+ if ((c & 0xc0) != 0xc0) -+ goto fail; -+ c &= 0x3f; -+ uchar |= c; -+ -+ /* no bogus surrogates */ -+ if (0xd800 <= uchar && uchar <= 0xdfff) -+ goto fail; -+ -+ // 4-byte sequence (surrogate pairs, currently rare): -+ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx -+ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx -+ // (uuuuu = wwww + 1) -+ // FIXME accept the surrogate code points (only) -+ } else -+ goto fail; -+ } else -+ uchar = c; -+ put_unaligned (cpu_to_le16 (uchar), cp++); -+ count++; -+ len--; -+ } -+ return count; -+fail: -+ return -1; -+} -+#endif /* DWC_UTFLIB */ -+ -+ -+/* dwc_debug.h */ -+ -+dwc_bool_t DWC_IN_IRQ(void) -+{ -+ return in_irq(); -+} -+ -+dwc_bool_t DWC_IN_BH(void) -+{ -+ return in_softirq(); -+} -+ -+void DWC_VPRINTF(char *format, va_list args) -+{ -+ vprintk(format, args); -+} -+ -+int DWC_VSNPRINTF(char *str, int size, char *format, va_list args) -+{ -+ return vsnprintf(str, size, format, args); -+} -+ -+void DWC_PRINTF(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+ -+int DWC_SPRINTF(char *buffer, char *format, ...) -+{ -+ int retval; -+ va_list args; -+ -+ va_start(args, format); -+ retval = vsprintf(buffer, format, args); -+ va_end(args); -+ return retval; -+} -+ -+int DWC_SNPRINTF(char *buffer, int size, char *format, ...) -+{ -+ int retval; -+ va_list args; -+ -+ va_start(args, format); -+ retval = vsnprintf(buffer, size, format, args); -+ va_end(args); -+ return retval; -+} -+ -+void __DWC_WARN(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_PRINTF(KERN_WARNING); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+ -+void __DWC_ERROR(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_PRINTF(KERN_ERR); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+ -+void DWC_EXCEPTION(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_PRINTF(KERN_ERR); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+ BUG_ON(1); -+} -+ -+#ifdef DEBUG -+void __DWC_DEBUG(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_PRINTF(KERN_DEBUG); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+#endif -+ -+ -+/* dwc_mem.h */ -+ -+#if 0 -+dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, -+ uint32_t align, -+ uint32_t alloc) -+{ -+ struct dma_pool *pool = dma_pool_create("Pool", NULL, -+ size, align, alloc); -+ return (dwc_pool_t *)pool; -+} -+ -+void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool) -+{ -+ dma_pool_destroy((struct dma_pool *)pool); -+} -+ -+void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr) -+{ -+ return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr); -+} -+ -+void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr) -+{ -+ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr); -+ memset(..); -+} -+ -+void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr) -+{ -+ dma_pool_free(pool, vaddr, daddr); -+} -+#endif -+ -+void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr) -+{ -+ return dma_alloc_coherent(dma_ctx, size, dma_addr, GFP_KERNEL | GFP_DMA32); -+} -+ -+void *__DWC_DMA_ALLOC_ATOMIC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr) -+{ -+ return dma_alloc_coherent(dma_ctx, size, dma_addr, GFP_ATOMIC); -+} -+ -+void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr) -+{ -+ dma_free_coherent(dma_ctx, size, virt_addr, dma_addr); -+} -+ -+void *__DWC_ALLOC(void *mem_ctx, uint32_t size) -+{ -+ return kzalloc(size, GFP_KERNEL); -+} -+ -+void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size) -+{ -+ return kzalloc(size, GFP_ATOMIC); -+} -+ -+void __DWC_FREE(void *mem_ctx, void *addr) -+{ -+ kfree(addr); -+} -+ -+ -+#ifdef DWC_CRYPTOLIB -+/* dwc_crypto.h */ -+ -+void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length) -+{ -+ get_random_bytes(buffer, length); -+} -+ -+int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t keylen, uint8_t iv[16], uint8_t *out) -+{ -+ struct crypto_blkcipher *tfm; -+ struct blkcipher_desc desc; -+ struct scatterlist sgd; -+ struct scatterlist sgs; -+ -+ tfm = crypto_alloc_blkcipher("cbc(aes)", 0, CRYPTO_ALG_ASYNC); -+ if (tfm == NULL) { -+ printk("failed to load transform for aes CBC\n"); -+ return -1; -+ } -+ -+ crypto_blkcipher_setkey(tfm, key, keylen); -+ crypto_blkcipher_set_iv(tfm, iv, 16); -+ -+ sg_init_one(&sgd, out, messagelen); -+ sg_init_one(&sgs, message, messagelen); -+ -+ desc.tfm = tfm; -+ desc.flags = 0; -+ -+ if (crypto_blkcipher_encrypt(&desc, &sgd, &sgs, messagelen)) { -+ crypto_free_blkcipher(tfm); -+ DWC_ERROR("AES CBC encryption failed"); -+ return -1; -+ } -+ -+ crypto_free_blkcipher(tfm); -+ return 0; -+} -+ -+int DWC_SHA256(uint8_t *message, uint32_t len, uint8_t *out) -+{ -+ struct crypto_hash *tfm; -+ struct hash_desc desc; -+ struct scatterlist sg; -+ -+ tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); -+ if (IS_ERR(tfm)) { -+ DWC_ERROR("Failed to load transform for sha256: %ld\n", PTR_ERR(tfm)); -+ return 0; -+ } -+ desc.tfm = tfm; -+ desc.flags = 0; -+ -+ sg_init_one(&sg, message, len); -+ crypto_hash_digest(&desc, &sg, len, out); -+ crypto_free_hash(tfm); -+ -+ return 1; -+} -+ -+int DWC_HMAC_SHA256(uint8_t *message, uint32_t messagelen, -+ uint8_t *key, uint32_t keylen, uint8_t *out) -+{ -+ struct crypto_hash *tfm; -+ struct hash_desc desc; -+ struct scatterlist sg; -+ -+ tfm = crypto_alloc_hash("hmac(sha256)", 0, CRYPTO_ALG_ASYNC); -+ if (IS_ERR(tfm)) { -+ DWC_ERROR("Failed to load transform for hmac(sha256): %ld\n", PTR_ERR(tfm)); -+ return 0; -+ } -+ desc.tfm = tfm; -+ desc.flags = 0; -+ -+ sg_init_one(&sg, message, messagelen); -+ crypto_hash_setkey(tfm, key, keylen); -+ crypto_hash_digest(&desc, &sg, messagelen, out); -+ crypto_free_hash(tfm); -+ -+ return 1; -+} -+#endif /* DWC_CRYPTOLIB */ -+ -+ -+/* Byte Ordering Conversions */ -+ -+uint32_t DWC_CPU_TO_LE32(uint32_t *p) -+{ -+#ifdef __LITTLE_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ -+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); -+#endif -+} -+ -+uint32_t DWC_CPU_TO_BE32(uint32_t *p) -+{ -+#ifdef __BIG_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ -+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); -+#endif -+} -+ -+uint32_t DWC_LE32_TO_CPU(uint32_t *p) -+{ -+#ifdef __LITTLE_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ -+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); -+#endif -+} -+ -+uint32_t DWC_BE32_TO_CPU(uint32_t *p) -+{ -+#ifdef __BIG_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ -+ return (u_p[3] | (u_p[2] << 8) | (u_p[1] << 16) | (u_p[0] << 24)); -+#endif -+} -+ -+uint16_t DWC_CPU_TO_LE16(uint16_t *p) -+{ -+#ifdef __LITTLE_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ return (u_p[1] | (u_p[0] << 8)); -+#endif -+} -+ -+uint16_t DWC_CPU_TO_BE16(uint16_t *p) -+{ -+#ifdef __BIG_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ return (u_p[1] | (u_p[0] << 8)); -+#endif -+} -+ -+uint16_t DWC_LE16_TO_CPU(uint16_t *p) -+{ -+#ifdef __LITTLE_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ return (u_p[1] | (u_p[0] << 8)); -+#endif -+} -+ -+uint16_t DWC_BE16_TO_CPU(uint16_t *p) -+{ -+#ifdef __BIG_ENDIAN -+ return *p; -+#else -+ uint8_t *u_p = (uint8_t *)p; -+ return (u_p[1] | (u_p[0] << 8)); -+#endif -+} -+ -+ -+/* Registers */ -+ -+uint32_t DWC_READ_REG32(uint32_t volatile *reg) -+{ -+ return readl(reg); -+} -+ -+#if 0 -+uint64_t DWC_READ_REG64(uint64_t volatile *reg) -+{ -+} -+#endif -+ -+void DWC_WRITE_REG32(uint32_t volatile *reg, uint32_t value) -+{ -+ writel(value, reg); -+} -+ -+#if 0 -+void DWC_WRITE_REG64(uint64_t volatile *reg, uint64_t value) -+{ -+} -+#endif -+ -+void DWC_MODIFY_REG32(uint32_t volatile *reg, uint32_t clear_mask, uint32_t set_mask) -+{ -+ writel((readl(reg) & ~clear_mask) | set_mask, reg); -+} -+ -+#if 0 -+void DWC_MODIFY_REG64(uint64_t volatile *reg, uint64_t clear_mask, uint64_t set_mask) -+{ -+} -+#endif -+ -+ -+/* Locking */ -+ -+dwc_spinlock_t *DWC_SPINLOCK_ALLOC(void) -+{ -+ spinlock_t *sl = (spinlock_t *)1; -+ -+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) -+ sl = DWC_ALLOC(sizeof(*sl)); -+ if (!sl) { -+ DWC_ERROR("Cannot allocate memory for spinlock\n"); -+ return NULL; -+ } -+ -+ spin_lock_init(sl); -+#endif -+ return (dwc_spinlock_t *)sl; -+} -+ -+void DWC_SPINLOCK_FREE(dwc_spinlock_t *lock) -+{ -+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) -+ DWC_FREE(lock); -+#endif -+} -+ -+void DWC_SPINLOCK(dwc_spinlock_t *lock) -+{ -+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) -+ spin_lock((spinlock_t *)lock); -+#endif -+} -+ -+void DWC_SPINUNLOCK(dwc_spinlock_t *lock) -+{ -+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) -+ spin_unlock((spinlock_t *)lock); -+#endif -+} -+ -+void DWC_SPINLOCK_IRQSAVE(dwc_spinlock_t *lock, dwc_irqflags_t *flags) -+{ -+ dwc_irqflags_t f; -+ -+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) -+ spin_lock_irqsave((spinlock_t *)lock, f); -+#else -+ local_irq_save(f); -+#endif -+ *flags = f; -+} -+ -+void DWC_SPINUNLOCK_IRQRESTORE(dwc_spinlock_t *lock, dwc_irqflags_t flags) -+{ -+#if defined(CONFIG_PREEMPT) || defined(CONFIG_SMP) -+ spin_unlock_irqrestore((spinlock_t *)lock, flags); -+#else -+ local_irq_restore(flags); -+#endif -+} -+ -+dwc_mutex_t *DWC_MUTEX_ALLOC(void) -+{ -+ struct mutex *m; -+ dwc_mutex_t *mutex = (dwc_mutex_t *)DWC_ALLOC(sizeof(struct mutex)); -+ -+ if (!mutex) { -+ DWC_ERROR("Cannot allocate memory for mutex\n"); -+ return NULL; -+ } -+ -+ m = (struct mutex *)mutex; -+ mutex_init(m); -+ return mutex; -+} -+ -+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_MUTEXES)) -+#else -+void DWC_MUTEX_FREE(dwc_mutex_t *mutex) -+{ -+ mutex_destroy((struct mutex *)mutex); -+ DWC_FREE(mutex); -+} -+#endif -+ -+void DWC_MUTEX_LOCK(dwc_mutex_t *mutex) -+{ -+ struct mutex *m = (struct mutex *)mutex; -+ mutex_lock(m); -+} -+ -+int DWC_MUTEX_TRYLOCK(dwc_mutex_t *mutex) -+{ -+ struct mutex *m = (struct mutex *)mutex; -+ return mutex_trylock(m); -+} -+ -+void DWC_MUTEX_UNLOCK(dwc_mutex_t *mutex) -+{ -+ struct mutex *m = (struct mutex *)mutex; -+ mutex_unlock(m); -+} -+ -+ -+/* Timing */ -+ -+void DWC_UDELAY(uint32_t usecs) -+{ -+ udelay(usecs); -+} -+ -+void DWC_MDELAY(uint32_t msecs) -+{ -+ mdelay(msecs); -+} -+ -+void DWC_MSLEEP(uint32_t msecs) -+{ -+ msleep(msecs); -+} -+ -+uint32_t DWC_TIME(void) -+{ -+ return jiffies_to_msecs(jiffies); -+} -+ -+ -+/* Timers */ -+ -+struct dwc_timer { -+ struct timer_list t; -+ char *name; -+ dwc_timer_callback_t cb; -+ void *data; -+ uint8_t scheduled; -+ dwc_spinlock_t *lock; -+}; -+ -+static void timer_callback(struct timer_list *tt) -+{ -+ dwc_timer_t *timer = from_timer(timer, tt, t); -+ dwc_irqflags_t flags; -+ -+ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags); -+ timer->scheduled = 0; -+ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags); -+ DWC_DEBUGC("Timer %s callback", timer->name); -+ timer->cb(timer->data); -+} -+ -+dwc_timer_t *DWC_TIMER_ALLOC(char *name, dwc_timer_callback_t cb, void *data) -+{ -+ dwc_timer_t *t = DWC_ALLOC(sizeof(*t)); -+ -+ if (!t) { -+ DWC_ERROR("Cannot allocate memory for timer"); -+ return NULL; -+ } -+ -+ t->name = DWC_STRDUP(name); -+ if (!t->name) { -+ DWC_ERROR("Cannot allocate memory for timer->name"); -+ goto no_name; -+ } -+ -+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK)) -+ DWC_SPINLOCK_ALLOC_LINUX_DEBUG(t->lock); -+#else -+ t->lock = DWC_SPINLOCK_ALLOC(); -+#endif -+ if (!t->lock) { -+ DWC_ERROR("Cannot allocate memory for lock"); -+ goto no_lock; -+ } -+ -+ t->scheduled = 0; -+ t->t.expires = jiffies; -+ timer_setup(&t->t, timer_callback, 0); -+ -+ t->cb = cb; -+ t->data = data; -+ -+ return t; -+ -+ no_lock: -+ DWC_FREE(t->name); -+ no_name: -+ DWC_FREE(t); -+ return NULL; -+} -+ -+void DWC_TIMER_FREE(dwc_timer_t *timer) -+{ -+ dwc_irqflags_t flags; -+ -+ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags); -+ -+ if (timer->scheduled) { -+ del_timer(&timer->t); -+ timer->scheduled = 0; -+ } -+ -+ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags); -+ DWC_SPINLOCK_FREE(timer->lock); -+ DWC_FREE(timer->name); -+ DWC_FREE(timer); -+} -+ -+void DWC_TIMER_SCHEDULE(dwc_timer_t *timer, uint32_t time) -+{ -+ dwc_irqflags_t flags; -+ -+ DWC_SPINLOCK_IRQSAVE(timer->lock, &flags); -+ -+ if (!timer->scheduled) { -+ timer->scheduled = 1; -+ DWC_DEBUGC("Scheduling timer %s to expire in +%d msec", timer->name, time); -+ timer->t.expires = jiffies + msecs_to_jiffies(time); -+ add_timer(&timer->t); -+ } else { -+ DWC_DEBUGC("Modifying timer %s to expire in +%d msec", timer->name, time); -+ mod_timer(&timer->t, jiffies + msecs_to_jiffies(time)); -+ } -+ -+ DWC_SPINUNLOCK_IRQRESTORE(timer->lock, flags); -+} -+ -+void DWC_TIMER_CANCEL(dwc_timer_t *timer) -+{ -+ del_timer(&timer->t); -+} -+ -+ -+/* Wait Queues */ -+ -+struct dwc_waitq { -+ wait_queue_head_t queue; -+ int abort; -+}; -+ -+dwc_waitq_t *DWC_WAITQ_ALLOC(void) -+{ -+ dwc_waitq_t *wq = DWC_ALLOC(sizeof(*wq)); -+ -+ if (!wq) { -+ DWC_ERROR("Cannot allocate memory for waitqueue\n"); -+ return NULL; -+ } -+ -+ init_waitqueue_head(&wq->queue); -+ wq->abort = 0; -+ return wq; -+} -+ -+void DWC_WAITQ_FREE(dwc_waitq_t *wq) -+{ -+ DWC_FREE(wq); -+} -+ -+int32_t DWC_WAITQ_WAIT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, void *data) -+{ -+ int result = wait_event_interruptible(wq->queue, -+ cond(data) || wq->abort); -+ if (result == -ERESTARTSYS) { -+ wq->abort = 0; -+ return -DWC_E_RESTART; -+ } -+ -+ if (wq->abort == 1) { -+ wq->abort = 0; -+ return -DWC_E_ABORT; -+ } -+ -+ wq->abort = 0; -+ -+ if (result == 0) { -+ return 0; -+ } -+ -+ return -DWC_E_UNKNOWN; -+} -+ -+int32_t DWC_WAITQ_WAIT_TIMEOUT(dwc_waitq_t *wq, dwc_waitq_condition_t cond, -+ void *data, int32_t msecs) -+{ -+ int32_t tmsecs; -+ int result = wait_event_interruptible_timeout(wq->queue, -+ cond(data) || wq->abort, -+ msecs_to_jiffies(msecs)); -+ if (result == -ERESTARTSYS) { -+ wq->abort = 0; -+ return -DWC_E_RESTART; -+ } -+ -+ if (wq->abort == 1) { -+ wq->abort = 0; -+ return -DWC_E_ABORT; -+ } -+ -+ wq->abort = 0; -+ -+ if (result > 0) { -+ tmsecs = jiffies_to_msecs(result); -+ if (!tmsecs) { -+ return 1; -+ } -+ -+ return tmsecs; -+ } -+ -+ if (result == 0) { -+ return -DWC_E_TIMEOUT; -+ } -+ -+ return -DWC_E_UNKNOWN; -+} -+ -+void DWC_WAITQ_TRIGGER(dwc_waitq_t *wq) -+{ -+ wq->abort = 0; -+ wake_up_interruptible(&wq->queue); -+} -+ -+void DWC_WAITQ_ABORT(dwc_waitq_t *wq) -+{ -+ wq->abort = 1; -+ wake_up_interruptible(&wq->queue); -+} -+ -+ -+/* Threading */ -+ -+dwc_thread_t *DWC_THREAD_RUN(dwc_thread_function_t func, char *name, void *data) -+{ -+ struct task_struct *thread = kthread_run(func, data, name); -+ -+ if (thread == ERR_PTR(-ENOMEM)) { -+ return NULL; -+ } -+ -+ return (dwc_thread_t *)thread; -+} -+ -+int DWC_THREAD_STOP(dwc_thread_t *thread) -+{ -+ return kthread_stop((struct task_struct *)thread); -+} -+ -+dwc_bool_t DWC_THREAD_SHOULD_STOP(void) -+{ -+ return kthread_should_stop(); -+} -+ -+ -+/* tasklets -+ - run in interrupt context (cannot sleep) -+ - each tasklet runs on a single CPU -+ - different tasklets can be running simultaneously on different CPUs -+ */ -+struct dwc_tasklet { -+ struct tasklet_struct t; -+ dwc_tasklet_callback_t cb; -+ void *data; -+}; -+ -+static void tasklet_callback(unsigned long data) -+{ -+ dwc_tasklet_t *t = (dwc_tasklet_t *)data; -+ t->cb(t->data); -+} -+ -+dwc_tasklet_t *DWC_TASK_ALLOC(char *name, dwc_tasklet_callback_t cb, void *data) -+{ -+ dwc_tasklet_t *t = DWC_ALLOC(sizeof(*t)); -+ -+ if (t) { -+ t->cb = cb; -+ t->data = data; -+ tasklet_init(&t->t, tasklet_callback, (unsigned long)t); -+ } else { -+ DWC_ERROR("Cannot allocate memory for tasklet\n"); -+ } -+ -+ return t; -+} -+ -+void DWC_TASK_FREE(dwc_tasklet_t *task) -+{ -+ DWC_FREE(task); -+} -+ -+void DWC_TASK_SCHEDULE(dwc_tasklet_t *task) -+{ -+ tasklet_schedule(&task->t); -+} -+ -+void DWC_TASK_HI_SCHEDULE(dwc_tasklet_t *task) -+{ -+ tasklet_hi_schedule(&task->t); -+} -+ -+ -+/* workqueues -+ - run in process context (can sleep) -+ */ -+typedef struct work_container { -+ dwc_work_callback_t cb; -+ void *data; -+ dwc_workq_t *wq; -+ char *name; -+ -+#ifdef DEBUG -+ DWC_CIRCLEQ_ENTRY(work_container) entry; -+#endif -+ struct delayed_work work; -+} work_container_t; -+ -+#ifdef DEBUG -+DWC_CIRCLEQ_HEAD(work_container_queue, work_container); -+#endif -+ -+struct dwc_workq { -+ struct workqueue_struct *wq; -+ dwc_spinlock_t *lock; -+ dwc_waitq_t *waitq; -+ int pending; -+ -+#ifdef DEBUG -+ struct work_container_queue entries; -+#endif -+}; -+ -+static void do_work(struct work_struct *work) -+{ -+ dwc_irqflags_t flags; -+ struct delayed_work *dw = container_of(work, struct delayed_work, work); -+ work_container_t *container = container_of(dw, struct work_container, work); -+ dwc_workq_t *wq = container->wq; -+ -+ container->cb(container->data); -+ -+#ifdef DEBUG -+ DWC_CIRCLEQ_REMOVE(&wq->entries, container, entry); -+#endif -+ DWC_DEBUGC("Work done: %s, container=%p", container->name, container); -+ if (container->name) { -+ DWC_FREE(container->name); -+ } -+ DWC_FREE(container); -+ -+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags); -+ wq->pending--; -+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags); -+ DWC_WAITQ_TRIGGER(wq->waitq); -+} -+ -+static int work_done(void *data) -+{ -+ dwc_workq_t *workq = (dwc_workq_t *)data; -+ return workq->pending == 0; -+} -+ -+int DWC_WORKQ_WAIT_WORK_DONE(dwc_workq_t *workq, int timeout) -+{ -+ return DWC_WAITQ_WAIT_TIMEOUT(workq->waitq, work_done, workq, timeout); -+} -+ -+dwc_workq_t *DWC_WORKQ_ALLOC(char *name) -+{ -+ dwc_workq_t *wq = DWC_ALLOC(sizeof(*wq)); -+ -+ if (!wq) { -+ return NULL; -+ } -+ -+ wq->wq = create_singlethread_workqueue(name); -+ if (!wq->wq) { -+ goto no_wq; -+ } -+ -+ wq->pending = 0; -+ -+#if (defined(DWC_LINUX) && defined(CONFIG_DEBUG_SPINLOCK)) -+ DWC_SPINLOCK_ALLOC_LINUX_DEBUG(wq->lock); -+#else -+ wq->lock = DWC_SPINLOCK_ALLOC(); -+#endif -+ if (!wq->lock) { -+ goto no_lock; -+ } -+ -+ wq->waitq = DWC_WAITQ_ALLOC(); -+ if (!wq->waitq) { -+ goto no_waitq; -+ } -+ -+#ifdef DEBUG -+ DWC_CIRCLEQ_INIT(&wq->entries); -+#endif -+ return wq; -+ -+ no_waitq: -+ DWC_SPINLOCK_FREE(wq->lock); -+ no_lock: -+ destroy_workqueue(wq->wq); -+ no_wq: -+ DWC_FREE(wq); -+ -+ return NULL; -+} -+ -+void DWC_WORKQ_FREE(dwc_workq_t *wq) -+{ -+#ifdef DEBUG -+ if (wq->pending != 0) { -+ struct work_container *wc; -+ DWC_ERROR("Destroying work queue with pending work"); -+ DWC_CIRCLEQ_FOREACH(wc, &wq->entries, entry) { -+ DWC_ERROR("Work %s still pending", wc->name); -+ } -+ } -+#endif -+ destroy_workqueue(wq->wq); -+ DWC_SPINLOCK_FREE(wq->lock); -+ DWC_WAITQ_FREE(wq->waitq); -+ DWC_FREE(wq); -+} -+ -+void DWC_WORKQ_SCHEDULE(dwc_workq_t *wq, dwc_work_callback_t cb, void *data, -+ char *format, ...) -+{ -+ dwc_irqflags_t flags; -+ work_container_t *container; -+ static char name[128]; -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VSNPRINTF(name, 128, format, args); -+ va_end(args); -+ -+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags); -+ wq->pending++; -+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags); -+ DWC_WAITQ_TRIGGER(wq->waitq); -+ -+ container = DWC_ALLOC_ATOMIC(sizeof(*container)); -+ if (!container) { -+ DWC_ERROR("Cannot allocate memory for container\n"); -+ return; -+ } -+ -+ container->name = DWC_STRDUP(name); -+ if (!container->name) { -+ DWC_ERROR("Cannot allocate memory for container->name\n"); -+ DWC_FREE(container); -+ return; -+ } -+ -+ container->cb = cb; -+ container->data = data; -+ container->wq = wq; -+ DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container); -+ INIT_WORK(&container->work.work, do_work); -+ -+#ifdef DEBUG -+ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry); -+#endif -+ queue_work(wq->wq, &container->work.work); -+} -+ -+void DWC_WORKQ_SCHEDULE_DELAYED(dwc_workq_t *wq, dwc_work_callback_t cb, -+ void *data, uint32_t time, char *format, ...) -+{ -+ dwc_irqflags_t flags; -+ work_container_t *container; -+ static char name[128]; -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VSNPRINTF(name, 128, format, args); -+ va_end(args); -+ -+ DWC_SPINLOCK_IRQSAVE(wq->lock, &flags); -+ wq->pending++; -+ DWC_SPINUNLOCK_IRQRESTORE(wq->lock, flags); -+ DWC_WAITQ_TRIGGER(wq->waitq); -+ -+ container = DWC_ALLOC_ATOMIC(sizeof(*container)); -+ if (!container) { -+ DWC_ERROR("Cannot allocate memory for container\n"); -+ return; -+ } -+ -+ container->name = DWC_STRDUP(name); -+ if (!container->name) { -+ DWC_ERROR("Cannot allocate memory for container->name\n"); -+ DWC_FREE(container); -+ return; -+ } -+ -+ container->cb = cb; -+ container->data = data; -+ container->wq = wq; -+ DWC_DEBUGC("Queueing work: %s, container=%p", container->name, container); -+ INIT_DELAYED_WORK(&container->work, do_work); -+ -+#ifdef DEBUG -+ DWC_CIRCLEQ_INSERT_TAIL(&wq->entries, container, entry); -+#endif -+ queue_delayed_work(wq->wq, &container->work, msecs_to_jiffies(time)); -+} -+ -+int DWC_WORKQ_PENDING(dwc_workq_t *wq) -+{ -+ return wq->pending; -+} -+ -+ -+#ifdef DWC_LIBMODULE -+ -+#ifdef DWC_CCLIB -+/* CC */ -+EXPORT_SYMBOL(dwc_cc_if_alloc); -+EXPORT_SYMBOL(dwc_cc_if_free); -+EXPORT_SYMBOL(dwc_cc_clear); -+EXPORT_SYMBOL(dwc_cc_add); -+EXPORT_SYMBOL(dwc_cc_remove); -+EXPORT_SYMBOL(dwc_cc_change); -+EXPORT_SYMBOL(dwc_cc_data_for_save); -+EXPORT_SYMBOL(dwc_cc_restore_from_data); -+EXPORT_SYMBOL(dwc_cc_match_chid); -+EXPORT_SYMBOL(dwc_cc_match_cdid); -+EXPORT_SYMBOL(dwc_cc_ck); -+EXPORT_SYMBOL(dwc_cc_chid); -+EXPORT_SYMBOL(dwc_cc_cdid); -+EXPORT_SYMBOL(dwc_cc_name); -+#endif /* DWC_CCLIB */ -+ -+#ifdef DWC_CRYPTOLIB -+# ifndef CONFIG_MACH_IPMATE -+/* Modpow */ -+EXPORT_SYMBOL(dwc_modpow); -+ -+/* DH */ -+EXPORT_SYMBOL(dwc_dh_modpow); -+EXPORT_SYMBOL(dwc_dh_derive_keys); -+EXPORT_SYMBOL(dwc_dh_pk); -+# endif /* CONFIG_MACH_IPMATE */ -+ -+/* Crypto */ -+EXPORT_SYMBOL(dwc_wusb_aes_encrypt); -+EXPORT_SYMBOL(dwc_wusb_cmf); -+EXPORT_SYMBOL(dwc_wusb_prf); -+EXPORT_SYMBOL(dwc_wusb_fill_ccm_nonce); -+EXPORT_SYMBOL(dwc_wusb_gen_nonce); -+EXPORT_SYMBOL(dwc_wusb_gen_key); -+EXPORT_SYMBOL(dwc_wusb_gen_mic); -+#endif /* DWC_CRYPTOLIB */ -+ -+/* Notification */ -+#ifdef DWC_NOTIFYLIB -+EXPORT_SYMBOL(dwc_alloc_notification_manager); -+EXPORT_SYMBOL(dwc_free_notification_manager); -+EXPORT_SYMBOL(dwc_register_notifier); -+EXPORT_SYMBOL(dwc_unregister_notifier); -+EXPORT_SYMBOL(dwc_add_observer); -+EXPORT_SYMBOL(dwc_remove_observer); -+EXPORT_SYMBOL(dwc_notify); -+#endif -+ -+/* Memory Debugging Routines */ -+#ifdef DWC_DEBUG_MEMORY -+EXPORT_SYMBOL(dwc_alloc_debug); -+EXPORT_SYMBOL(dwc_alloc_atomic_debug); -+EXPORT_SYMBOL(dwc_free_debug); -+EXPORT_SYMBOL(dwc_dma_alloc_debug); -+EXPORT_SYMBOL(dwc_dma_free_debug); -+#endif -+ -+EXPORT_SYMBOL(DWC_MEMSET); -+EXPORT_SYMBOL(DWC_MEMCPY); -+EXPORT_SYMBOL(DWC_MEMMOVE); -+EXPORT_SYMBOL(DWC_MEMCMP); -+EXPORT_SYMBOL(DWC_STRNCMP); -+EXPORT_SYMBOL(DWC_STRCMP); -+EXPORT_SYMBOL(DWC_STRLEN); -+EXPORT_SYMBOL(DWC_STRCPY); -+EXPORT_SYMBOL(DWC_STRDUP); -+EXPORT_SYMBOL(DWC_ATOI); -+EXPORT_SYMBOL(DWC_ATOUI); -+ -+#ifdef DWC_UTFLIB -+EXPORT_SYMBOL(DWC_UTF8_TO_UTF16LE); -+#endif /* DWC_UTFLIB */ -+ -+EXPORT_SYMBOL(DWC_IN_IRQ); -+EXPORT_SYMBOL(DWC_IN_BH); -+EXPORT_SYMBOL(DWC_VPRINTF); -+EXPORT_SYMBOL(DWC_VSNPRINTF); -+EXPORT_SYMBOL(DWC_PRINTF); -+EXPORT_SYMBOL(DWC_SPRINTF); -+EXPORT_SYMBOL(DWC_SNPRINTF); -+EXPORT_SYMBOL(__DWC_WARN); -+EXPORT_SYMBOL(__DWC_ERROR); -+EXPORT_SYMBOL(DWC_EXCEPTION); -+ -+#ifdef DEBUG -+EXPORT_SYMBOL(__DWC_DEBUG); -+#endif -+ -+EXPORT_SYMBOL(__DWC_DMA_ALLOC); -+EXPORT_SYMBOL(__DWC_DMA_ALLOC_ATOMIC); -+EXPORT_SYMBOL(__DWC_DMA_FREE); -+EXPORT_SYMBOL(__DWC_ALLOC); -+EXPORT_SYMBOL(__DWC_ALLOC_ATOMIC); -+EXPORT_SYMBOL(__DWC_FREE); -+ -+#ifdef DWC_CRYPTOLIB -+EXPORT_SYMBOL(DWC_RANDOM_BYTES); -+EXPORT_SYMBOL(DWC_AES_CBC); -+EXPORT_SYMBOL(DWC_SHA256); -+EXPORT_SYMBOL(DWC_HMAC_SHA256); -+#endif -+ -+EXPORT_SYMBOL(DWC_CPU_TO_LE32); -+EXPORT_SYMBOL(DWC_CPU_TO_BE32); -+EXPORT_SYMBOL(DWC_LE32_TO_CPU); -+EXPORT_SYMBOL(DWC_BE32_TO_CPU); -+EXPORT_SYMBOL(DWC_CPU_TO_LE16); -+EXPORT_SYMBOL(DWC_CPU_TO_BE16); -+EXPORT_SYMBOL(DWC_LE16_TO_CPU); -+EXPORT_SYMBOL(DWC_BE16_TO_CPU); -+EXPORT_SYMBOL(DWC_READ_REG32); -+EXPORT_SYMBOL(DWC_WRITE_REG32); -+EXPORT_SYMBOL(DWC_MODIFY_REG32); -+ -+#if 0 -+EXPORT_SYMBOL(DWC_READ_REG64); -+EXPORT_SYMBOL(DWC_WRITE_REG64); -+EXPORT_SYMBOL(DWC_MODIFY_REG64); -+#endif -+ -+EXPORT_SYMBOL(DWC_SPINLOCK_ALLOC); -+EXPORT_SYMBOL(DWC_SPINLOCK_FREE); -+EXPORT_SYMBOL(DWC_SPINLOCK); -+EXPORT_SYMBOL(DWC_SPINUNLOCK); -+EXPORT_SYMBOL(DWC_SPINLOCK_IRQSAVE); -+EXPORT_SYMBOL(DWC_SPINUNLOCK_IRQRESTORE); -+EXPORT_SYMBOL(DWC_MUTEX_ALLOC); -+ -+#if (!defined(DWC_LINUX) || !defined(CONFIG_DEBUG_MUTEXES)) -+EXPORT_SYMBOL(DWC_MUTEX_FREE); -+#endif -+ -+EXPORT_SYMBOL(DWC_MUTEX_LOCK); -+EXPORT_SYMBOL(DWC_MUTEX_TRYLOCK); -+EXPORT_SYMBOL(DWC_MUTEX_UNLOCK); -+EXPORT_SYMBOL(DWC_UDELAY); -+EXPORT_SYMBOL(DWC_MDELAY); -+EXPORT_SYMBOL(DWC_MSLEEP); -+EXPORT_SYMBOL(DWC_TIME); -+EXPORT_SYMBOL(DWC_TIMER_ALLOC); -+EXPORT_SYMBOL(DWC_TIMER_FREE); -+EXPORT_SYMBOL(DWC_TIMER_SCHEDULE); -+EXPORT_SYMBOL(DWC_TIMER_CANCEL); -+EXPORT_SYMBOL(DWC_WAITQ_ALLOC); -+EXPORT_SYMBOL(DWC_WAITQ_FREE); -+EXPORT_SYMBOL(DWC_WAITQ_WAIT); -+EXPORT_SYMBOL(DWC_WAITQ_WAIT_TIMEOUT); -+EXPORT_SYMBOL(DWC_WAITQ_TRIGGER); -+EXPORT_SYMBOL(DWC_WAITQ_ABORT); -+EXPORT_SYMBOL(DWC_THREAD_RUN); -+EXPORT_SYMBOL(DWC_THREAD_STOP); -+EXPORT_SYMBOL(DWC_THREAD_SHOULD_STOP); -+EXPORT_SYMBOL(DWC_TASK_ALLOC); -+EXPORT_SYMBOL(DWC_TASK_FREE); -+EXPORT_SYMBOL(DWC_TASK_SCHEDULE); -+EXPORT_SYMBOL(DWC_WORKQ_WAIT_WORK_DONE); -+EXPORT_SYMBOL(DWC_WORKQ_ALLOC); -+EXPORT_SYMBOL(DWC_WORKQ_FREE); -+EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE); -+EXPORT_SYMBOL(DWC_WORKQ_SCHEDULE_DELAYED); -+EXPORT_SYMBOL(DWC_WORKQ_PENDING); -+ -+static int dwc_common_port_init_module(void) -+{ -+ int result = 0; -+ -+ printk(KERN_DEBUG "Module dwc_common_port init\n" ); -+ -+#ifdef DWC_DEBUG_MEMORY -+ result = dwc_memory_debug_start(NULL); -+ if (result) { -+ printk(KERN_ERR -+ "dwc_memory_debug_start() failed with error %d\n", -+ result); -+ return result; -+ } -+#endif -+ -+#ifdef DWC_NOTIFYLIB -+ result = dwc_alloc_notification_manager(NULL, NULL); -+ if (result) { -+ printk(KERN_ERR -+ "dwc_alloc_notification_manager() failed with error %d\n", -+ result); -+ return result; -+ } -+#endif -+ return result; -+} -+ -+static void dwc_common_port_exit_module(void) -+{ -+ printk(KERN_DEBUG "Module dwc_common_port exit\n" ); -+ -+#ifdef DWC_NOTIFYLIB -+ dwc_free_notification_manager(); -+#endif -+ -+#ifdef DWC_DEBUG_MEMORY -+ dwc_memory_debug_stop(); -+#endif -+} -+ -+module_init(dwc_common_port_init_module); -+module_exit(dwc_common_port_exit_module); -+ -+MODULE_DESCRIPTION("DWC Common Library - Portable version"); -+MODULE_AUTHOR("Synopsys Inc."); -+MODULE_LICENSE ("GPL"); -+ -+#endif /* DWC_LIBMODULE */ -diff --git a/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c -new file mode 100644 -index 000000000000..49b07e172264 ---- /dev/null -+++ b/drivers/usb/host/dwc_common_port/dwc_common_nbsd.c -@@ -0,0 +1,1275 @@ -+#include "dwc_os.h" -+#include "dwc_list.h" -+ -+#ifdef DWC_CCLIB -+# include "dwc_cc.h" -+#endif -+ -+#ifdef DWC_CRYPTOLIB -+# include "dwc_modpow.h" -+# include "dwc_dh.h" -+# include "dwc_crypto.h" -+#endif -+ -+#ifdef DWC_NOTIFYLIB -+# include "dwc_notifier.h" -+#endif -+ -+/* OS-Level Implementations */ -+ -+/* This is the NetBSD 4.0.1 kernel implementation of the DWC platform library. */ -+ -+ -+/* MISC */ -+ -+void *DWC_MEMSET(void *dest, uint8_t byte, uint32_t size) -+{ -+ return memset(dest, byte, size); -+} -+ -+void *DWC_MEMCPY(void *dest, void const *src, uint32_t size) -+{ -+ return memcpy(dest, src, size); -+} -+ -+void *DWC_MEMMOVE(void *dest, void *src, uint32_t size) -+{ -+ bcopy(src, dest, size); -+ return dest; -+} -+ -+int DWC_MEMCMP(void *m1, void *m2, uint32_t size) -+{ -+ return memcmp(m1, m2, size); -+} -+ -+int DWC_STRNCMP(void *s1, void *s2, uint32_t size) -+{ -+ return strncmp(s1, s2, size); -+} -+ -+int DWC_STRCMP(void *s1, void *s2) -+{ -+ return strcmp(s1, s2); -+} -+ -+int DWC_STRLEN(char const *str) -+{ -+ return strlen(str); -+} -+ -+char *DWC_STRCPY(char *to, char const *from) -+{ -+ return strcpy(to, from); -+} -+ -+char *DWC_STRDUP(char const *str) -+{ -+ int len = DWC_STRLEN(str) + 1; -+ char *new = DWC_ALLOC_ATOMIC(len); -+ -+ if (!new) { -+ return NULL; -+ } -+ -+ DWC_MEMCPY(new, str, len); -+ return new; -+} -+ -+int DWC_ATOI(char *str, int32_t *value) -+{ -+ char *end = NULL; -+ -+ /* NetBSD doesn't have 'strtol' in the kernel, but 'strtoul' -+ * should be equivalent on 2's complement machines -+ */ -+ *value = strtoul(str, &end, 0); -+ if (*end == '\0') { -+ return 0; -+ } -+ -+ return -1; -+} -+ -+int DWC_ATOUI(char *str, uint32_t *value) -+{ -+ char *end = NULL; -+ -+ *value = strtoul(str, &end, 0); -+ if (*end == '\0') { -+ return 0; -+ } -+ -+ return -1; -+} -+ -+ -+#ifdef DWC_UTFLIB -+/* From usbstring.c */ -+ -+int DWC_UTF8_TO_UTF16LE(uint8_t const *s, uint16_t *cp, unsigned len) -+{ -+ int count = 0; -+ u8 c; -+ u16 uchar; -+ -+ /* this insists on correct encodings, though not minimal ones. -+ * BUT it currently rejects legit 4-byte UTF-8 code points, -+ * which need surrogate pairs. (Unicode 3.1 can use them.) -+ */ -+ while (len != 0 && (c = (u8) *s++) != 0) { -+ if (unlikely(c & 0x80)) { -+ // 2-byte sequence: -+ // 00000yyyyyxxxxxx = 110yyyyy 10xxxxxx -+ if ((c & 0xe0) == 0xc0) { -+ uchar = (c & 0x1f) << 6; -+ -+ c = (u8) *s++; -+ if ((c & 0xc0) != 0xc0) -+ goto fail; -+ c &= 0x3f; -+ uchar |= c; -+ -+ // 3-byte sequence (most CJKV characters): -+ // zzzzyyyyyyxxxxxx = 1110zzzz 10yyyyyy 10xxxxxx -+ } else if ((c & 0xf0) == 0xe0) { -+ uchar = (c & 0x0f) << 12; -+ -+ c = (u8) *s++; -+ if ((c & 0xc0) != 0xc0) -+ goto fail; -+ c &= 0x3f; -+ uchar |= c << 6; -+ -+ c = (u8) *s++; -+ if ((c & 0xc0) != 0xc0) -+ goto fail; -+ c &= 0x3f; -+ uchar |= c; -+ -+ /* no bogus surrogates */ -+ if (0xd800 <= uchar && uchar <= 0xdfff) -+ goto fail; -+ -+ // 4-byte sequence (surrogate pairs, currently rare): -+ // 11101110wwwwzzzzyy + 110111yyyyxxxxxx -+ // = 11110uuu 10uuzzzz 10yyyyyy 10xxxxxx -+ // (uuuuu = wwww + 1) -+ // FIXME accept the surrogate code points (only) -+ } else -+ goto fail; -+ } else -+ uchar = c; -+ put_unaligned (cpu_to_le16 (uchar), cp++); -+ count++; -+ len--; -+ } -+ return count; -+fail: -+ return -1; -+} -+ -+#endif /* DWC_UTFLIB */ -+ -+ -+/* dwc_debug.h */ -+ -+dwc_bool_t DWC_IN_IRQ(void) -+{ -+// return in_irq(); -+ return 0; -+} -+ -+dwc_bool_t DWC_IN_BH(void) -+{ -+// return in_softirq(); -+ return 0; -+} -+ -+void DWC_VPRINTF(char *format, va_list args) -+{ -+ vprintf(format, args); -+} -+ -+int DWC_VSNPRINTF(char *str, int size, char *format, va_list args) -+{ -+ return vsnprintf(str, size, format, args); -+} -+ -+void DWC_PRINTF(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+ -+int DWC_SPRINTF(char *buffer, char *format, ...) -+{ -+ int retval; -+ va_list args; -+ -+ va_start(args, format); -+ retval = vsprintf(buffer, format, args); -+ va_end(args); -+ return retval; -+} -+ -+int DWC_SNPRINTF(char *buffer, int size, char *format, ...) -+{ -+ int retval; -+ va_list args; -+ -+ va_start(args, format); -+ retval = vsnprintf(buffer, size, format, args); -+ va_end(args); -+ return retval; -+} -+ -+void __DWC_WARN(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+ -+void __DWC_ERROR(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+ -+void DWC_EXCEPTION(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+// BUG_ON(1); ??? -+} -+ -+#ifdef DEBUG -+void __DWC_DEBUG(char *format, ...) -+{ -+ va_list args; -+ -+ va_start(args, format); -+ DWC_VPRINTF(format, args); -+ va_end(args); -+} -+#endif -+ -+ -+/* dwc_mem.h */ -+ -+#if 0 -+dwc_pool_t *DWC_DMA_POOL_CREATE(uint32_t size, -+ uint32_t align, -+ uint32_t alloc) -+{ -+ struct dma_pool *pool = dma_pool_create("Pool", NULL, -+ size, align, alloc); -+ return (dwc_pool_t *)pool; -+} -+ -+void DWC_DMA_POOL_DESTROY(dwc_pool_t *pool) -+{ -+ dma_pool_destroy((struct dma_pool *)pool); -+} -+ -+void *DWC_DMA_POOL_ALLOC(dwc_pool_t *pool, uint64_t *dma_addr) -+{ -+// return dma_pool_alloc((struct dma_pool *)pool, GFP_KERNEL, dma_addr); -+ return dma_pool_alloc((struct dma_pool *)pool, M_WAITOK, dma_addr); -+} -+ -+void *DWC_DMA_POOL_ZALLOC(dwc_pool_t *pool, uint64_t *dma_addr) -+{ -+ void *vaddr = DWC_DMA_POOL_ALLOC(pool, dma_addr); -+ memset(..); -+} -+ -+void DWC_DMA_POOL_FREE(dwc_pool_t *pool, void *vaddr, void *daddr) -+{ -+ dma_pool_free(pool, vaddr, daddr); -+} -+#endif -+ -+void *__DWC_DMA_ALLOC(void *dma_ctx, uint32_t size, dwc_dma_t *dma_addr) -+{ -+ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx; -+ int error; -+ -+ error = bus_dmamem_alloc(dma->dma_tag, size, 1, size, dma->segs, -+ sizeof(dma->segs) / sizeof(dma->segs[0]), -+ &dma->nsegs, BUS_DMA_NOWAIT); -+ if (error) { -+ printf("%s: bus_dmamem_alloc(%ju) failed: %d\n", __func__, -+ (uintmax_t)size, error); -+ goto fail_0; -+ } -+ -+ error = bus_dmamem_map(dma->dma_tag, dma->segs, dma->nsegs, size, -+ (caddr_t *)&dma->dma_vaddr, -+ BUS_DMA_NOWAIT | BUS_DMA_COHERENT); -+ if (error) { -+ printf("%s: bus_dmamem_map failed: %d\n", __func__, error); -+ goto fail_1; -+ } -+ -+ error = bus_dmamap_create(dma->dma_tag, size, 1, size, 0, -+ BUS_DMA_NOWAIT, &dma->dma_map); -+ if (error) { -+ printf("%s: bus_dmamap_create failed: %d\n", __func__, error); -+ goto fail_2; -+ } -+ -+ error = bus_dmamap_load(dma->dma_tag, dma->dma_map, dma->dma_vaddr, -+ size, NULL, BUS_DMA_NOWAIT); -+ if (error) { -+ printf("%s: bus_dmamap_load failed: %d\n", __func__, error); -+ goto fail_3; -+ } -+ -+ dma->dma_paddr = (bus_addr_t)dma->segs[0].ds_addr; -+ *dma_addr = dma->dma_paddr; -+ return dma->dma_vaddr; -+ -+fail_3: -+ bus_dmamap_destroy(dma->dma_tag, dma->dma_map); -+fail_2: -+ bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size); -+fail_1: -+ bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs); -+fail_0: -+ dma->dma_map = NULL; -+ dma->dma_vaddr = NULL; -+ dma->nsegs = 0; -+ -+ return NULL; -+} -+ -+void __DWC_DMA_FREE(void *dma_ctx, uint32_t size, void *virt_addr, dwc_dma_t dma_addr) -+{ -+ dwc_dmactx_t *dma = (dwc_dmactx_t *)dma_ctx; -+ -+ if (dma->dma_map != NULL) { -+ bus_dmamap_sync(dma->dma_tag, dma->dma_map, 0, size, -+ BUS_DMASYNC_POSTREAD | BUS_DMASYNC_POSTWRITE); -+ bus_dmamap_unload(dma->dma_tag, dma->dma_map); -+ bus_dmamap_destroy(dma->dma_tag, dma->dma_map); -+ bus_dmamem_unmap(dma->dma_tag, dma->dma_vaddr, size); -+ bus_dmamem_free(dma->dma_tag, dma->segs, dma->nsegs); -+ dma->dma_paddr = 0; -+ dma->dma_map = NULL; -+ dma->dma_vaddr = NULL; -+ dma->nsegs = 0; -+ } -+} -+ -+void *__DWC_ALLOC(void *mem_ctx, uint32_t size) -+{ -+ return malloc(size, M_DEVBUF, M_WAITOK | M_ZERO); -+} -+ -+void *__DWC_ALLOC_ATOMIC(void *mem_ctx, uint32_t size) -+{ -+ return malloc(size, M_DEVBUF, M_NOWAIT | M_ZERO); -+} -+ -+void __DWC_FREE(void *mem_ctx, void *addr) -+{ -+ free(addr, M_DEVBUF); -+} -+ -+ -+#ifdef DWC_CRYPTOLIB -+/* dwc_crypto.h */ -+ -+void DWC_RANDOM_BYTES(uint8_t *buffer, uint32_t length) -+{ -+ get_random_bytes(buffer, length); -+} -+ -+int DWC_AES_CBC(uint8_t *message, uint32_t messagelen, uint8_t *key, uint32_t key |