From 23e049442b7b4f87f802470b4fd46a0e50b2fbdd Mon Sep 17 00:00:00 2001 From: Andrew Morton Date: Tue, 1 Nov 2011 00:53:33 -0400 Subject: drivers/net/ethernet/i825xx/3c505.c: fix build with dynamic debug The `#define filename' screws up the expansion of DEFINE_DYNAMIC_DEBUG_METADATA: drivers/net/ethernet/i825xx/3c505.c: In function 'send_pcb': drivers/net/ethernet/i825xx/3c505.c:390: error: expected identifier before string constant drivers/net/ethernet/i825xx/3c505.c:390: error: expected '}' before '.' token drivers/net/ethernet/i825xx/3c505.c:436: error: expected identifier before string constant drivers/net/ethernet/i825xx/3c505.c:435: error: expected '}' before '.' token drivers/net/ethernet/i825xx/3c505.c: In function 'start_receive': drivers/net/ethernet/i825xx/3c505.c:557: error: expected identifier before string constant drivers/net/ethernet/i825xx/3c505.c:557: error: expected '}' before '.' token drivers/net/ethernet/i825xx/3c505.c: In function 'receive_packet': drivers/net/ethernet/i825xx/3c505.c:629: error: expected identifier before string constant etc So remove that #define and "open-code" it. Cc: Philip Blundell Cc: David Miller Cc: Jason Baron Signed-off-by: Andrew Morton Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/i825xx/3c505.c b/drivers/net/ethernet/i825xx/3c505.c index 40e1a17..ba82a26 100644 --- a/drivers/net/ethernet/i825xx/3c505.c +++ b/drivers/net/ethernet/i825xx/3c505.c @@ -126,15 +126,13 @@ * *********************************************************/ -#define filename __FILE__ - #define timeout_msg "*** timeout at %s:%s (line %d) ***\n" #define TIMEOUT_MSG(lineno) \ - pr_notice(timeout_msg, filename, __func__, (lineno)) + pr_notice(timeout_msg, __FILE__, __func__, (lineno)) #define invalid_pcb_msg "*** invalid pcb length %d at %s:%s (line %d) ***\n" #define INVALID_PCB_MSG(len) \ - pr_notice(invalid_pcb_msg, (len), filename, __func__, __LINE__) + pr_notice(invalid_pcb_msg, (len), __FILE__, __func__, __LINE__) #define search_msg "%s: Looking for 3c505 adapter at address %#x..." -- cgit v0.10.2 From f83347df57113e54e999aa2491be3f685c0c262d Mon Sep 17 00:00:00 2001 From: Marcos Paulo de Souza Date: Mon, 31 Oct 2011 15:11:45 +0000 Subject: include: linux: skbuf.h: Fix parameter documentation Fixes parameter name of skb_frag_dmamap function to silence warning on make htmldocs. Signed-off-by: Marcos Paulo de Souza Signed-off-by: David S. Miller diff --git a/include/linux/skbuff.h b/include/linux/skbuff.h index 6a6b352..fe86488 100644 --- a/include/linux/skbuff.h +++ b/include/linux/skbuff.h @@ -1806,12 +1806,12 @@ static inline void skb_frag_set_page(struct sk_buff *skb, int f, /** * skb_frag_dma_map - maps a paged fragment via the DMA API - * @device: the device to map the fragment to + * @dev: the device to map the fragment to * @frag: the paged fragment to map * @offset: the offset within the fragment (starting at the * fragment's own offset) * @size: the number of bytes to map - * @direction: the direction of the mapping (%PCI_DMA_*) + * @dir: the direction of the mapping (%PCI_DMA_*) * * Maps the page associated with @frag to @device. */ -- cgit v0.10.2 From 52669dfa8312b7f63b963df6d01dc5513398f4c4 Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczynski Date: Mon, 12 Sep 2011 10:15:15 +0100 Subject: ipvs: Expose ip_vs_ftp module parameters via sysfs. This is to expose "ports" parameter via sysfs so it can be read at any time in order to determine what port or ports were passed to the module at the point when it was loaded. Signed-off-by: Krzysztof Wilczynski Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/ipvs/ip_vs_ftp.c b/net/netfilter/ipvs/ip_vs_ftp.c index 4490a32..538d74e 100644 --- a/net/netfilter/ipvs/ip_vs_ftp.c +++ b/net/netfilter/ipvs/ip_vs_ftp.c @@ -52,8 +52,9 @@ * List of ports (up to IP_VS_APP_MAX_PORTS) to be handled by helper * First port is set to the default port. */ +static unsigned int ports_count = 1; static unsigned short ports[IP_VS_APP_MAX_PORTS] = {21, 0}; -module_param_array(ports, ushort, NULL, 0); +module_param_array(ports, ushort, &ports_count, 0444); MODULE_PARM_DESC(ports, "Ports to monitor for FTP control commands"); @@ -449,7 +450,7 @@ static int __net_init __ip_vs_ftp_init(struct net *net) if (ret) goto err_exit; - for (i=0; iprotocol, ports[i]); -- cgit v0.10.2 From 7e777dd43d55a78c41c3498afaf3ef7edf157120 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 9 Sep 2011 17:07:43 +0900 Subject: ipvs: Add documentation for new sysctl entries Add missing documentation for conntrack, snat_reroute and sync_version. Also fix up a typo, IPVS_DEBUG should be IP_VS_DEBUG. Acked-by: Julian Anastasov Acked-by Hans Schillstrom Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso diff --git a/Documentation/networking/ipvs-sysctl.txt b/Documentation/networking/ipvs-sysctl.txt index 4ccdbca..1dcdd49 100644 --- a/Documentation/networking/ipvs-sysctl.txt +++ b/Documentation/networking/ipvs-sysctl.txt @@ -15,6 +15,23 @@ amemthresh - INTEGER enabled and the variable is automatically set to 2, otherwise the strategy is disabled and the variable is set to 1. +conntrack - BOOLEAN + 0 - disabled (default) + not 0 - enabled + + If set, maintain connection tracking entries for + connections handled by IPVS. + + This should be enabled if connections handled by IPVS are to be + also handled by stateful firewall rules. That is, iptables rules + that make use of connection tracking. It is a performance + optimisation to disable this setting otherwise. + + Connections handled by the IPVS FTP application module + will have connection tracking entries regardless of this setting. + + Only available when IPVS is compiled with the CONFIG_IP_VS_NFCT + cache_bypass - BOOLEAN 0 - disabled (default) not 0 - enabled @@ -39,7 +56,7 @@ debug_level - INTEGER 11 - IPVS packet handling (ip_vs_in/ip_vs_out) 12 or more - packet traversal - Only available when IPVS is compiled with the CONFIG_IPVS_DEBUG + Only available when IPVS is compiled with the CONFIG_IP_VS_DEBUG Higher debugging levels include the messages for lower debugging levels, so setting debug level 2, includes level 0, 1 and 2 @@ -141,3 +158,36 @@ sync_threshold - INTEGER synchronized, every time the number of its incoming packets modulus 50 equals the threshold. The range of the threshold is from 0 to 49. + +snat_reroute - BOOLEAN + 0 - disabled + not 0 - enabled (default) + + If enabled, recalculate the route of SNATed packets from + realservers so that they are routed as if they originate from the + director. Otherwise they are routed as if they are forwarded by the + director. + + If policy routing is in effect then it is possible that the route + of a packet originating from a director is routed differently to a + packet being forwarded by the director. + + If policy routing is not in effect then the recalculated route will + always be the same as the original route so it is an optimisation + to disable snat_reroute and avoid the recalculation. + +sync_version - INTEGER + default 1 + + The version of the synchronisation protocol used when sending + synchronisation messages. + + 0 selects the original synchronisation protocol (version 0). This + should be used when sending synchronisation messages to a legacy + system that only understands the original synchronisation protocol. + + 1 selects the current synchronisation protocol (version 1). This + should be used where possible. + + Kernels with this sync_version entry are able to receive messages + of both version 1 and version 2 of the synchronisation protocol. -- cgit v0.10.2 From 3c2de2ae028d2325a3f4fa47a43e099d6049194d Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 16 Sep 2011 14:02:19 +0900 Subject: ipvs: Remove unused parameter from ip_vs_confirm_conntrack() Acked-by: Julian Anastasov Acked-by Hans Schillstrom Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index 8fa4430..c4058bd 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -1378,7 +1378,7 @@ static inline int ip_vs_conntrack_enabled(struct netns_ipvs *ipvs) extern void ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, int outin); -extern int ip_vs_confirm_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp); +extern int ip_vs_confirm_conntrack(struct sk_buff *skb); extern void ip_vs_nfct_expect_related(struct sk_buff *skb, struct nf_conn *ct, struct ip_vs_conn *cp, u_int8_t proto, const __be16 port, int from_rs); @@ -1396,8 +1396,7 @@ static inline void ip_vs_update_conntrack(struct sk_buff *skb, { } -static inline int ip_vs_confirm_conntrack(struct sk_buff *skb, - struct ip_vs_conn *cp) +static inline int ip_vs_confirm_conntrack(struct sk_buff *skb); { return NF_ACCEPT; } diff --git a/net/netfilter/ipvs/ip_vs_nfct.c b/net/netfilter/ipvs/ip_vs_nfct.c index f454c80..022e77e 100644 --- a/net/netfilter/ipvs/ip_vs_nfct.c +++ b/net/netfilter/ipvs/ip_vs_nfct.c @@ -127,7 +127,7 @@ ip_vs_update_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp, int outin) nf_conntrack_alter_reply(ct, &new_tuple); } -int ip_vs_confirm_conntrack(struct sk_buff *skb, struct ip_vs_conn *cp) +int ip_vs_confirm_conntrack(struct sk_buff *skb) { return nf_conntrack_confirm(skb); } diff --git a/net/netfilter/ipvs/ip_vs_xmit.c b/net/netfilter/ipvs/ip_vs_xmit.c index ee319a4..aa2d720 100644 --- a/net/netfilter/ipvs/ip_vs_xmit.c +++ b/net/netfilter/ipvs/ip_vs_xmit.c @@ -339,7 +339,7 @@ ip_vs_dst_reset(struct ip_vs_dest *dest) \ (skb)->ipvs_property = 1; \ if (unlikely((cp)->flags & IP_VS_CONN_F_NFCT)) \ - __ret = ip_vs_confirm_conntrack(skb, cp); \ + __ret = ip_vs_confirm_conntrack(skb); \ if (__ret == NF_ACCEPT) { \ nf_reset(skb); \ skb_forward_csum(skb); \ -- cgit v0.10.2 From 4a516f1108070db94dbfc88c80b8b6942915f1f2 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 16 Sep 2011 14:11:49 +0900 Subject: ipvs: Remove unused return value of protocol state transitions Acked-by: Julian Anastasov Acked-by Hans Schillstrom Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index c4058bd..a6b8b47 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -425,9 +425,9 @@ struct ip_vs_protocol { const char *(*state_name)(int state); - int (*state_transition)(struct ip_vs_conn *cp, int direction, - const struct sk_buff *skb, - struct ip_vs_proto_data *pd); + void (*state_transition)(struct ip_vs_conn *cp, int direction, + const struct sk_buff *skb, + struct ip_vs_proto_data *pd); int (*register_app)(struct net *net, struct ip_vs_app *inc); diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 4f77bb1..00ea1ad 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -188,14 +188,13 @@ ip_vs_conn_stats(struct ip_vs_conn *cp, struct ip_vs_service *svc) } -static inline int +static inline void ip_vs_set_state(struct ip_vs_conn *cp, int direction, const struct sk_buff *skb, struct ip_vs_proto_data *pd) { - if (unlikely(!pd->pp->state_transition)) - return 0; - return pd->pp->state_transition(cp, direction, skb, pd); + if (likely(pd->pp->state_transition)) + pd->pp->state_transition(cp, direction, skb, pd); } static inline int @@ -557,7 +556,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, ip_vs_in_stats(cp, skb); /* set state */ - cs = ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd); + ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd); /* transmit the first SYN packet */ ret = cp->packet_xmit(skb, cp, pd->pp); @@ -1490,7 +1489,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) struct ip_vs_protocol *pp; struct ip_vs_proto_data *pd; struct ip_vs_conn *cp; - int ret, restart, pkts; + int ret, pkts; struct netns_ipvs *ipvs; /* Already marked as IPVS request or reply? */ @@ -1591,7 +1590,7 @@ ip_vs_in(unsigned int hooknum, struct sk_buff *skb, int af) } ip_vs_in_stats(cp, skb); - restart = ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd); + ip_vs_set_state(cp, IP_VS_DIR_INPUT, skb, pd); if (cp->packet_xmit) ret = cp->packet_xmit(skb, cp, pp); /* do not touch skb anymore */ diff --git a/net/netfilter/ipvs/ip_vs_proto_sctp.c b/net/netfilter/ipvs/ip_vs_proto_sctp.c index d12ed53..1fbf7a2 100644 --- a/net/netfilter/ipvs/ip_vs_proto_sctp.c +++ b/net/netfilter/ipvs/ip_vs_proto_sctp.c @@ -906,7 +906,7 @@ static const char *sctp_state_name(int state) return "?"; } -static inline int +static inline void set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, int direction, const struct sk_buff *skb) { @@ -924,7 +924,7 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, sch = skb_header_pointer(skb, ihl + sizeof(sctp_sctphdr_t), sizeof(_sctpch), &_sctpch); if (sch == NULL) - return 0; + return; chunk_type = sch->type; /* @@ -993,21 +993,15 @@ set_sctp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, cp->timeout = pd->timeout_table[cp->state = next_state]; else /* What to do ? */ cp->timeout = sctp_timeouts[cp->state = next_state]; - - return 1; } -static int +static void sctp_state_transition(struct ip_vs_conn *cp, int direction, const struct sk_buff *skb, struct ip_vs_proto_data *pd) { - int ret = 0; - spin_lock(&cp->lock); - ret = set_sctp_state(pd, cp, direction, skb); + set_sctp_state(pd, cp, direction, skb); spin_unlock(&cp->lock); - - return ret; } static inline __u16 sctp_app_hashkey(__be16 port) diff --git a/net/netfilter/ipvs/ip_vs_proto_tcp.c b/net/netfilter/ipvs/ip_vs_proto_tcp.c index c0cc341..ef8641f 100644 --- a/net/netfilter/ipvs/ip_vs_proto_tcp.c +++ b/net/netfilter/ipvs/ip_vs_proto_tcp.c @@ -546,7 +546,7 @@ set_tcp_state(struct ip_vs_proto_data *pd, struct ip_vs_conn *cp, /* * Handle state transitions */ -static int +static void tcp_state_transition(struct ip_vs_conn *cp, int direction, const struct sk_buff *skb, struct ip_vs_proto_data *pd) @@ -561,13 +561,11 @@ tcp_state_transition(struct ip_vs_conn *cp, int direction, th = skb_header_pointer(skb, ihl, sizeof(_tcph), &_tcph); if (th == NULL) - return 0; + return; spin_lock(&cp->lock); set_tcp_state(pd, cp, direction, th); spin_unlock(&cp->lock); - - return 1; } static inline __u16 tcp_app_hashkey(__be16 port) diff --git a/net/netfilter/ipvs/ip_vs_proto_udp.c b/net/netfilter/ipvs/ip_vs_proto_udp.c index f1282cb..f4b7262 100644 --- a/net/netfilter/ipvs/ip_vs_proto_udp.c +++ b/net/netfilter/ipvs/ip_vs_proto_udp.c @@ -454,18 +454,17 @@ static const char * udp_state_name(int state) return udp_state_name_table[state] ? udp_state_name_table[state] : "?"; } -static int +static void udp_state_transition(struct ip_vs_conn *cp, int direction, const struct sk_buff *skb, struct ip_vs_proto_data *pd) { if (unlikely(!pd)) { pr_err("UDP no ns data\n"); - return 0; + return; } cp->timeout = pd->timeout_table[IP_VS_UDP_S_NORMAL]; - return 1; } static void __udp_init(struct net *net, struct ip_vs_proto_data *pd) -- cgit v0.10.2 From b6338b55bd2e7c51a46b23150695d821ae6626d8 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Fri, 16 Sep 2011 14:17:20 +0900 Subject: ipvs: Removed unused variables ipvs is not used in ip_vs_genl_set_cmd() or ip_vs_genl_get_cmd() Acked-by: Julian Anastasov Acked-by Hans Schillstrom Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index e3be48b..993935c 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -3326,10 +3326,8 @@ static int ip_vs_genl_set_cmd(struct sk_buff *skb, struct genl_info *info) int ret = 0, cmd; int need_full_svc = 0, need_full_dest = 0; struct net *net; - struct netns_ipvs *ipvs; net = skb_sknet(skb); - ipvs = net_ipvs(net); cmd = info->genlhdr->cmd; mutex_lock(&__ip_vs_mutex); @@ -3421,10 +3419,8 @@ static int ip_vs_genl_get_cmd(struct sk_buff *skb, struct genl_info *info) void *reply; int ret, cmd, reply_cmd; struct net *net; - struct netns_ipvs *ipvs; net = skb_sknet(skb); - ipvs = net_ipvs(net); cmd = info->genlhdr->cmd; if (cmd == IPVS_CMD_GET_SERVICE) -- cgit v0.10.2 From 325aadc8483e4fc3bbd4acfa7e471e3a032bc941 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 29 Sep 2011 16:14:51 +0900 Subject: ipvs: secure_tcp does provide alternate state timeouts Also reword the test to make it read more easily (to me) Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso diff --git a/Documentation/networking/ipvs-sysctl.txt b/Documentation/networking/ipvs-sysctl.txt index 1dcdd49..13610e3 100644 --- a/Documentation/networking/ipvs-sysctl.txt +++ b/Documentation/networking/ipvs-sysctl.txt @@ -140,13 +140,11 @@ nat_icmp_send - BOOLEAN secure_tcp - INTEGER 0 - disabled (default) - The secure_tcp defense is to use a more complicated state - transition table and some possible short timeouts of each - state. In the VS/NAT, it delays the entering the ESTABLISHED - until the real server starts to send data and ACK packet - (after 3-way handshake). + The secure_tcp defense is to use a more complicated TCP state + transition table. For VS/NAT, it also delays entering the + TCP ESTABLISHED state until the three way handshake is completed. - The value definition is the same as that of drop_entry or + The value definition is the same as that of drop_entry and drop_packet. sync_threshold - INTEGER -- cgit v0.10.2 From 40cb1f9bc52186a1a9ef56f0d976482863516ce1 Mon Sep 17 00:00:00 2001 From: Simon Horman Date: Thu, 29 Sep 2011 16:27:37 +0900 Subject: ipvs: Enhance grammar used to refer to Kconfig options Reported-by: Randy Dunlap Signed-off-by: Simon Horman Signed-off-by: Pablo Neira Ayuso diff --git a/Documentation/networking/ipvs-sysctl.txt b/Documentation/networking/ipvs-sysctl.txt index 13610e3..f2a2488 100644 --- a/Documentation/networking/ipvs-sysctl.txt +++ b/Documentation/networking/ipvs-sysctl.txt @@ -30,7 +30,7 @@ conntrack - BOOLEAN Connections handled by the IPVS FTP application module will have connection tracking entries regardless of this setting. - Only available when IPVS is compiled with the CONFIG_IP_VS_NFCT + Only available when IPVS is compiled with CONFIG_IP_VS_NFCT enabled. cache_bypass - BOOLEAN 0 - disabled (default) @@ -56,7 +56,7 @@ debug_level - INTEGER 11 - IPVS packet handling (ip_vs_in/ip_vs_out) 12 or more - packet traversal - Only available when IPVS is compiled with the CONFIG_IP_VS_DEBUG + Only available when IPVS is compiled with CONFIG_IP_VS_DEBUG enabled. Higher debugging levels include the messages for lower debugging levels, so setting debug level 2, includes level 0, 1 and 2 -- cgit v0.10.2 From 0a9ee81349d90c6c85831f38118bf569c60a4d51 Mon Sep 17 00:00:00 2001 From: Joe Perches Date: Mon, 29 Aug 2011 14:17:25 -0700 Subject: netfilter: Remove unnecessary OOM logging messages Site specific OOM messages are duplications of a generic MM out of memory message and aren't really useful, so just delete them. Signed-off-by: Joe Perches Signed-off-by: Patrick McHardy Signed-off-by: Pablo Neira Ayuso diff --git a/net/bridge/netfilter/ebt_ulog.c b/net/bridge/netfilter/ebt_ulog.c index bf2a333..5449294 100644 --- a/net/bridge/netfilter/ebt_ulog.c +++ b/net/bridge/netfilter/ebt_ulog.c @@ -102,16 +102,15 @@ static struct sk_buff *ulog_alloc_skb(unsigned int size) unsigned int n; n = max(size, nlbufsiz); - skb = alloc_skb(n, GFP_ATOMIC); + skb = alloc_skb(n, GFP_ATOMIC | __GFP_NOWARN); if (!skb) { - pr_debug("cannot alloc whole buffer of size %ub!\n", n); if (n > size) { /* try to allocate only as much as we need for * current packet */ skb = alloc_skb(size, GFP_ATOMIC); if (!skb) - pr_debug("cannot even allocate " - "buffer of size %ub\n", size); + pr_debug("cannot even allocate buffer of size %ub\n", + size); } } diff --git a/net/ipv4/netfilter/ipt_CLUSTERIP.c b/net/ipv4/netfilter/ipt_CLUSTERIP.c index db8d22d..a639967 100644 --- a/net/ipv4/netfilter/ipt_CLUSTERIP.c +++ b/net/ipv4/netfilter/ipt_CLUSTERIP.c @@ -395,7 +395,6 @@ static int clusterip_tg_check(const struct xt_tgchk_param *par) config = clusterip_config_init(cipinfo, e->ip.dst.s_addr, dev); if (!config) { - pr_info("cannot allocate config\n"); dev_put(dev); return -ENOMEM; } diff --git a/net/ipv4/netfilter/ipt_ULOG.c b/net/ipv4/netfilter/ipt_ULOG.c index 446e0f4..b550815 100644 --- a/net/ipv4/netfilter/ipt_ULOG.c +++ b/net/ipv4/netfilter/ipt_ULOG.c @@ -135,10 +135,8 @@ static struct sk_buff *ulog_alloc_skb(unsigned int size) * due to slab allocator restrictions */ n = max(size, nlbufsiz); - skb = alloc_skb(n, GFP_ATOMIC); + skb = alloc_skb(n, GFP_ATOMIC | __GFP_NOWARN); if (!skb) { - pr_debug("cannot alloc whole buffer %ub!\n", n); - if (n > size) { /* try to allocate only as much as we need for * current packet */ diff --git a/net/ipv4/netfilter/nf_nat_snmp_basic.c b/net/ipv4/netfilter/nf_nat_snmp_basic.c index d1cb412..2133c30 100644 --- a/net/ipv4/netfilter/nf_nat_snmp_basic.c +++ b/net/ipv4/netfilter/nf_nat_snmp_basic.c @@ -400,11 +400,8 @@ static unsigned char asn1_octets_decode(struct asn1_ctx *ctx, *len = 0; *octets = kmalloc(eoc - ctx->pointer, GFP_ATOMIC); - if (*octets == NULL) { - if (net_ratelimit()) - pr_notice("OOM in bsalg (%d)\n", __LINE__); + if (*octets == NULL) return 0; - } ptr = *octets; while (ctx->pointer < eoc) { @@ -451,11 +448,8 @@ static unsigned char asn1_oid_decode(struct asn1_ctx *ctx, return 0; *oid = kmalloc(size * sizeof(unsigned long), GFP_ATOMIC); - if (*oid == NULL) { - if (net_ratelimit()) - pr_notice("OOM in bsalg (%d)\n", __LINE__); + if (*oid == NULL) return 0; - } optr = *oid; @@ -728,8 +722,6 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); if (*obj == NULL) { kfree(id); - if (net_ratelimit()) - pr_notice("OOM in bsalg (%d)\n", __LINE__); return 0; } (*obj)->syntax.l[0] = l; @@ -744,8 +736,6 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, if (*obj == NULL) { kfree(p); kfree(id); - if (net_ratelimit()) - pr_notice("OOM in bsalg (%d)\n", __LINE__); return 0; } memcpy((*obj)->syntax.c, p, len); @@ -759,8 +749,6 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, *obj = kmalloc(sizeof(struct snmp_object), GFP_ATOMIC); if (*obj == NULL) { kfree(id); - if (net_ratelimit()) - pr_notice("OOM in bsalg (%d)\n", __LINE__); return 0; } if (!asn1_null_decode(ctx, end)) { @@ -780,8 +768,6 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, if (*obj == NULL) { kfree(lp); kfree(id); - if (net_ratelimit()) - pr_notice("OOM in bsalg (%d)\n", __LINE__); return 0; } memcpy((*obj)->syntax.ul, lp, len); @@ -801,8 +787,6 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, if (*obj == NULL) { kfree(p); kfree(id); - if (net_ratelimit()) - pr_notice("OOM in bsalg (%d)\n", __LINE__); return 0; } memcpy((*obj)->syntax.uc, p, len); @@ -819,8 +803,6 @@ static unsigned char snmp_object_decode(struct asn1_ctx *ctx, *obj = kmalloc(sizeof(struct snmp_object) + len, GFP_ATOMIC); if (*obj == NULL) { kfree(id); - if (net_ratelimit()) - pr_notice("OOM in bsalg (%d)\n", __LINE__); return 0; } (*obj)->syntax.ul[0] = ul; diff --git a/net/ipv6/netfilter/nf_conntrack_reasm.c b/net/ipv6/netfilter/nf_conntrack_reasm.c index e8762c7..38f00b0 100644 --- a/net/ipv6/netfilter/nf_conntrack_reasm.c +++ b/net/ipv6/netfilter/nf_conntrack_reasm.c @@ -182,7 +182,6 @@ fq_find(__be32 id, u32 user, struct in6_addr *src, struct in6_addr *dst) return container_of(q, struct nf_ct_frag6_queue, q); oom: - pr_debug("Can't alloc new queue\n"); return NULL; } @@ -370,10 +369,10 @@ nf_ct_frag6_reasm(struct nf_ct_frag6_queue *fq, struct net_device *dev) struct sk_buff *clone; int i, plen = 0; - if ((clone = alloc_skb(0, GFP_ATOMIC)) == NULL) { - pr_debug("Can't alloc skb\n"); + clone = alloc_skb(0, GFP_ATOMIC); + if (clone == NULL) goto out_oom; - } + clone->next = head->next; head->next = clone; skb_shinfo(clone)->frag_list = skb_shinfo(head)->frag_list; diff --git a/net/netfilter/ipset/ip_set_core.c b/net/netfilter/ipset/ip_set_core.c index d7e86ef..86137b5 100644 --- a/net/netfilter/ipset/ip_set_core.c +++ b/net/netfilter/ipset/ip_set_core.c @@ -1699,10 +1699,8 @@ ip_set_init(void) ip_set_list = kzalloc(sizeof(struct ip_set *) * ip_set_max, GFP_KERNEL); - if (!ip_set_list) { - pr_err("ip_set: Unable to create ip_set_list\n"); + if (!ip_set_list) return -ENOMEM; - } ret = nfnetlink_subsys_register(&ip_set_netlink_subsys); if (ret != 0) { diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 00ea1ad..46a8130 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -1877,10 +1877,9 @@ static int __net_init __ip_vs_init(struct net *net) struct netns_ipvs *ipvs; ipvs = net_generic(net, ip_vs_net_id); - if (ipvs == NULL) { - pr_err("%s(): no memory.\n", __func__); + if (ipvs == NULL) return -ENOMEM; - } + /* Hold the beast until a service is registerd */ ipvs->enable = 0; ipvs->net = net; diff --git a/net/netfilter/ipvs/ip_vs_ctl.c b/net/netfilter/ipvs/ip_vs_ctl.c index 993935c..008bf97 100644 --- a/net/netfilter/ipvs/ip_vs_ctl.c +++ b/net/netfilter/ipvs/ip_vs_ctl.c @@ -856,15 +856,12 @@ ip_vs_new_dest(struct ip_vs_service *svc, struct ip_vs_dest_user_kern *udest, } dest = kzalloc(sizeof(struct ip_vs_dest), GFP_KERNEL); - if (dest == NULL) { - pr_err("%s(): no memory.\n", __func__); + if (dest == NULL) return -ENOMEM; - } + dest->stats.cpustats = alloc_percpu(struct ip_vs_cpu_stats); - if (!dest->stats.cpustats) { - pr_err("%s() alloc_percpu failed\n", __func__); + if (!dest->stats.cpustats) goto err_alloc; - } dest->af = svc->af; dest->protocol = svc->protocol; @@ -1168,10 +1165,8 @@ ip_vs_add_service(struct net *net, struct ip_vs_service_user_kern *u, goto out_err; } svc->stats.cpustats = alloc_percpu(struct ip_vs_cpu_stats); - if (!svc->stats.cpustats) { - pr_err("%s() alloc_percpu failed\n", __func__); + if (!svc->stats.cpustats) goto out_err; - } /* I'm the first user of the service */ atomic_set(&svc->usecnt, 0); @@ -3716,10 +3711,9 @@ int __net_init ip_vs_control_net_init(struct net *net) /* procfs stats */ ipvs->tot_stats.cpustats = alloc_percpu(struct ip_vs_cpu_stats); - if (!ipvs->tot_stats.cpustats) { - pr_err("%s(): alloc_percpu.\n", __func__); + if (!ipvs->tot_stats.cpustats) return -ENOMEM; - } + spin_lock_init(&ipvs->tot_stats.lock); proc_net_fops_create(net, "ip_vs", 0, &ip_vs_info_fops); diff --git a/net/netfilter/ipvs/ip_vs_dh.c b/net/netfilter/ipvs/ip_vs_dh.c index 95fd0d1..1c269e5 100644 --- a/net/netfilter/ipvs/ip_vs_dh.c +++ b/net/netfilter/ipvs/ip_vs_dh.c @@ -150,10 +150,9 @@ static int ip_vs_dh_init_svc(struct ip_vs_service *svc) /* allocate the DH table for this service */ tbl = kmalloc(sizeof(struct ip_vs_dh_bucket)*IP_VS_DH_TAB_SIZE, GFP_ATOMIC); - if (tbl == NULL) { - pr_err("%s(): no memory\n", __func__); + if (tbl == NULL) return -ENOMEM; - } + svc->sched_data = tbl; IP_VS_DBG(6, "DH hash table (memory=%Zdbytes) allocated for " "current service\n", diff --git a/net/netfilter/ipvs/ip_vs_lblc.c b/net/netfilter/ipvs/ip_vs_lblc.c index 87e40ea..0f16283 100644 --- a/net/netfilter/ipvs/ip_vs_lblc.c +++ b/net/netfilter/ipvs/ip_vs_lblc.c @@ -202,10 +202,8 @@ ip_vs_lblc_new(struct ip_vs_lblc_table *tbl, const union nf_inet_addr *daddr, en = ip_vs_lblc_get(dest->af, tbl, daddr); if (!en) { en = kmalloc(sizeof(*en), GFP_ATOMIC); - if (!en) { - pr_err("%s(): no memory\n", __func__); + if (!en) return NULL; - } en->af = dest->af; ip_vs_addr_copy(dest->af, &en->addr, daddr); @@ -345,10 +343,9 @@ static int ip_vs_lblc_init_svc(struct ip_vs_service *svc) * Allocate the ip_vs_lblc_table for this service */ tbl = kmalloc(sizeof(*tbl), GFP_ATOMIC); - if (tbl == NULL) { - pr_err("%s(): no memory\n", __func__); + if (tbl == NULL) return -ENOMEM; - } + svc->sched_data = tbl; IP_VS_DBG(6, "LBLC hash table (memory=%Zdbytes) allocated for " "current service\n", sizeof(*tbl)); diff --git a/net/netfilter/ipvs/ip_vs_lblcr.c b/net/netfilter/ipvs/ip_vs_lblcr.c index 90f618a..eec797f 100644 --- a/net/netfilter/ipvs/ip_vs_lblcr.c +++ b/net/netfilter/ipvs/ip_vs_lblcr.c @@ -112,10 +112,8 @@ ip_vs_dest_set_insert(struct ip_vs_dest_set *set, struct ip_vs_dest *dest) } e = kmalloc(sizeof(*e), GFP_ATOMIC); - if (e == NULL) { - pr_err("%s(): no memory\n", __func__); + if (e == NULL) return NULL; - } atomic_inc(&dest->refcnt); e->dest = dest; @@ -373,10 +371,8 @@ ip_vs_lblcr_new(struct ip_vs_lblcr_table *tbl, const union nf_inet_addr *daddr, en = ip_vs_lblcr_get(dest->af, tbl, daddr); if (!en) { en = kmalloc(sizeof(*en), GFP_ATOMIC); - if (!en) { - pr_err("%s(): no memory\n", __func__); + if (!en) return NULL; - } en->af = dest->af; ip_vs_addr_copy(dest->af, &en->addr, daddr); @@ -516,10 +512,9 @@ static int ip_vs_lblcr_init_svc(struct ip_vs_service *svc) * Allocate the ip_vs_lblcr_table for this service */ tbl = kmalloc(sizeof(*tbl), GFP_ATOMIC); - if (tbl == NULL) { - pr_err("%s(): no memory\n", __func__); + if (tbl == NULL) return -ENOMEM; - } + svc->sched_data = tbl; IP_VS_DBG(6, "LBLCR hash table (memory=%Zdbytes) allocated for " "current service\n", sizeof(*tbl)); diff --git a/net/netfilter/ipvs/ip_vs_proto.c b/net/netfilter/ipvs/ip_vs_proto.c index 52d073c..8531293 100644 --- a/net/netfilter/ipvs/ip_vs_proto.c +++ b/net/netfilter/ipvs/ip_vs_proto.c @@ -74,10 +74,9 @@ register_ip_vs_proto_netns(struct net *net, struct ip_vs_protocol *pp) struct ip_vs_proto_data *pd = kzalloc(sizeof(struct ip_vs_proto_data), GFP_ATOMIC); - if (!pd) { - pr_err("%s(): no memory.\n", __func__); + if (!pd) return -ENOMEM; - } + pd->pp = pp; /* For speed issues */ pd->next = ipvs->proto_data_table[hash]; ipvs->proto_data_table[hash] = pd; diff --git a/net/netfilter/ipvs/ip_vs_sh.c b/net/netfilter/ipvs/ip_vs_sh.c index b5e2556..33815f4 100644 --- a/net/netfilter/ipvs/ip_vs_sh.c +++ b/net/netfilter/ipvs/ip_vs_sh.c @@ -147,10 +147,9 @@ static int ip_vs_sh_init_svc(struct ip_vs_service *svc) /* allocate the SH table for this service */ tbl = kmalloc(sizeof(struct ip_vs_sh_bucket)*IP_VS_SH_TAB_SIZE, GFP_ATOMIC); - if (tbl == NULL) { - pr_err("%s(): no memory\n", __func__); + if (tbl == NULL) return -ENOMEM; - } + svc->sched_data = tbl; IP_VS_DBG(6, "SH hash table (memory=%Zdbytes) allocated for " "current service\n", diff --git a/net/netfilter/ipvs/ip_vs_wrr.c b/net/netfilter/ipvs/ip_vs_wrr.c index 1ef41f5..fd0d4e0 100644 --- a/net/netfilter/ipvs/ip_vs_wrr.c +++ b/net/netfilter/ipvs/ip_vs_wrr.c @@ -85,10 +85,9 @@ static int ip_vs_wrr_init_svc(struct ip_vs_service *svc) * Allocate the mark variable for WRR scheduling */ mark = kmalloc(sizeof(struct ip_vs_wrr_mark), GFP_ATOMIC); - if (mark == NULL) { - pr_err("%s(): no memory\n", __func__); + if (mark == NULL) return -ENOMEM; - } + mark->cl = &svc->destinations; mark->cw = 0; mark->mw = ip_vs_wrr_max_weight(svc); diff --git a/net/netfilter/nf_conntrack_core.c b/net/netfilter/nf_conntrack_core.c index 5acfaf5..7202b06 100644 --- a/net/netfilter/nf_conntrack_core.c +++ b/net/netfilter/nf_conntrack_core.c @@ -661,7 +661,6 @@ __nf_conntrack_alloc(struct net *net, u16 zone, */ ct = kmem_cache_alloc(net->ct.nf_conntrack_cachep, gfp); if (ct == NULL) { - pr_debug("nf_conntrack_alloc: Can't alloc conntrack.\n"); atomic_dec(&net->ct.count); return ERR_PTR(-ENOMEM); } @@ -749,10 +748,8 @@ init_conntrack(struct net *net, struct nf_conn *tmpl, ct = __nf_conntrack_alloc(net, zone, tuple, &repl_tuple, GFP_ATOMIC, hash); - if (IS_ERR(ct)) { - pr_debug("Can't allocate conntrack.\n"); + if (IS_ERR(ct)) return (struct nf_conntrack_tuple_hash *)ct; - } if (!l4proto->new(ct, skb, dataoff)) { nf_conntrack_free(ct); diff --git a/net/netfilter/nfnetlink_log.c b/net/netfilter/nfnetlink_log.c index 2d8158a..66b2c54 100644 --- a/net/netfilter/nfnetlink_log.c +++ b/net/netfilter/nfnetlink_log.c @@ -307,17 +307,14 @@ nfulnl_alloc_skb(unsigned int inst_size, unsigned int pkt_size) n = max(inst_size, pkt_size); skb = alloc_skb(n, GFP_ATOMIC); if (!skb) { - pr_notice("nfnetlink_log: can't alloc whole buffer (%u bytes)\n", - inst_size); - if (n > pkt_size) { /* try to allocate only as much as we need for current * packet */ skb = alloc_skb(pkt_size, GFP_ATOMIC); if (!skb) - pr_err("nfnetlink_log: can't even alloc %u " - "bytes\n", pkt_size); + pr_err("nfnetlink_log: can't even alloc %u bytes\n", + pkt_size); } } diff --git a/net/netfilter/xt_IDLETIMER.c b/net/netfilter/xt_IDLETIMER.c index 3bdd443..f407ebc1 100644 --- a/net/netfilter/xt_IDLETIMER.c +++ b/net/netfilter/xt_IDLETIMER.c @@ -122,14 +122,12 @@ static int idletimer_tg_create(struct idletimer_tg_info *info) info->timer = kmalloc(sizeof(*info->timer), GFP_KERNEL); if (!info->timer) { - pr_debug("couldn't alloc timer\n"); ret = -ENOMEM; goto out; } info->timer->attr.attr.name = kstrdup(info->label, GFP_KERNEL); if (!info->timer->attr.attr.name) { - pr_debug("couldn't alloc attribute name\n"); ret = -ENOMEM; goto out_free_timer; } diff --git a/net/netfilter/xt_hashlimit.c b/net/netfilter/xt_hashlimit.c index 9228ee0d..dfd52ba 100644 --- a/net/netfilter/xt_hashlimit.c +++ b/net/netfilter/xt_hashlimit.c @@ -176,10 +176,7 @@ dsthash_alloc_init(struct xt_hashlimit_htable *ht, ent = NULL; } else ent = kmem_cache_alloc(hashlimit_cachep, GFP_ATOMIC); - if (!ent) { - if (net_ratelimit()) - pr_err("cannot allocate dsthash_ent\n"); - } else { + if (ent) { memcpy(&ent->dst, dst, sizeof(ent->dst)); spin_lock_init(&ent->lock); -- cgit v0.10.2 From 8d83f63b19d45ba0898b97824afcc8e0b5c954cb Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Sat, 1 Oct 2011 13:51:29 -0400 Subject: netfilter: export NAT definitions through linux/netfilter_ipv4/nf_nat.h This patch exports several definitions that used to live under include/net/netfilter/nf_nat.h. These definitions, although not exported, have been used by iptables and other userspace applications like miniupnpd since long time. Basically, these userspace tools included some internal definition of the required structures and they assume no changes in the binary representation (which is OK indeed). To resolve this situation, this patch makes public the required structure and install them in INSTALL_HDR_PATH. See: https://bugs.gentoo.org/376873, for more information. This patch is heavily based on the initial patch sent by: Anthony G. Basile Which was entitled: netfilter: export sanitized nf_nat.h to INSTALL_HDR_PATH Signed-off-by: Pablo Neira Ayuso diff --git a/include/linux/netfilter_ipv4/Kbuild b/include/linux/netfilter_ipv4/Kbuild index f9930c8..c3b4548 100644 --- a/include/linux/netfilter_ipv4/Kbuild +++ b/include/linux/netfilter_ipv4/Kbuild @@ -12,3 +12,4 @@ header-y += ipt_ah.h header-y += ipt_ecn.h header-y += ipt_realm.h header-y += ipt_ttl.h +header-y += nf_nat.h diff --git a/include/linux/netfilter_ipv4/nf_nat.h b/include/linux/netfilter_ipv4/nf_nat.h new file mode 100644 index 0000000..7a861d0 --- /dev/null +++ b/include/linux/netfilter_ipv4/nf_nat.h @@ -0,0 +1,58 @@ +#ifndef _LINUX_NF_NAT_H +#define _LINUX_NF_NAT_H + +#include + +#define IP_NAT_RANGE_MAP_IPS 1 +#define IP_NAT_RANGE_PROTO_SPECIFIED 2 +#define IP_NAT_RANGE_PROTO_RANDOM 4 +#define IP_NAT_RANGE_PERSISTENT 8 + +/* The protocol-specific manipulable parts of the tuple. */ +union nf_conntrack_man_proto { + /* Add other protocols here. */ + __be16 all; + + struct { + __be16 port; + } tcp; + struct { + __be16 port; + } udp; + struct { + __be16 id; + } icmp; + struct { + __be16 port; + } dccp; + struct { + __be16 port; + } sctp; + struct { + __be16 key; /* GRE key is 32bit, PPtP only uses 16bit */ + } gre; +}; + +/* Single range specification. */ +struct nf_nat_range { + /* Set to OR of flags above. */ + unsigned int flags; + + /* Inclusive: network order. */ + __be32 min_ip, max_ip; + + /* Inclusive: network order */ + union nf_conntrack_man_proto min, max; +}; + +/* For backwards compat: don't use in modern code. */ +struct nf_nat_multi_range_compat { + unsigned int rangesize; /* Must be 1. */ + + /* hangs off end. */ + struct nf_nat_range range[1]; +}; + +#define nf_nat_multi_range nf_nat_multi_range_compat + +#endif diff --git a/include/net/netfilter/nf_conntrack_tuple.h b/include/net/netfilter/nf_conntrack_tuple.h index 7ca6bdd..2f8fb77 100644 --- a/include/net/netfilter/nf_conntrack_tuple.h +++ b/include/net/netfilter/nf_conntrack_tuple.h @@ -12,6 +12,7 @@ #include #include +#include #include /* A `tuple' is a structure containing the information to uniquely @@ -24,32 +25,6 @@ #define NF_CT_TUPLE_L3SIZE ARRAY_SIZE(((union nf_inet_addr *)NULL)->all) -/* The protocol-specific manipulable parts of the tuple: always in - network order! */ -union nf_conntrack_man_proto { - /* Add other protocols here. */ - __be16 all; - - struct { - __be16 port; - } tcp; - struct { - __be16 port; - } udp; - struct { - __be16 id; - } icmp; - struct { - __be16 port; - } dccp; - struct { - __be16 port; - } sctp; - struct { - __be16 key; /* GRE key is 32bit, PPtP only uses 16bit */ - } gre; -}; - /* The manipulable part of the tuple. */ struct nf_conntrack_man { union nf_inet_addr u3; diff --git a/include/net/netfilter/nf_nat.h b/include/net/netfilter/nf_nat.h index 0346b00..b8872df 100644 --- a/include/net/netfilter/nf_nat.h +++ b/include/net/netfilter/nf_nat.h @@ -1,6 +1,7 @@ #ifndef _NF_NAT_H #define _NF_NAT_H #include +#include #include #define NF_NAT_MAPPING_TYPE_MAX_NAMELEN 16 @@ -14,11 +15,6 @@ enum nf_nat_manip_type { #define HOOK2MANIP(hooknum) ((hooknum) != NF_INET_POST_ROUTING && \ (hooknum) != NF_INET_LOCAL_IN) -#define IP_NAT_RANGE_MAP_IPS 1 -#define IP_NAT_RANGE_PROTO_SPECIFIED 2 -#define IP_NAT_RANGE_PROTO_RANDOM 4 -#define IP_NAT_RANGE_PERSISTENT 8 - /* NAT sequence number modifications */ struct nf_nat_seq { /* position of the last TCP sequence number modification (if any) */ @@ -28,26 +24,6 @@ struct nf_nat_seq { int16_t offset_before, offset_after; }; -/* Single range specification. */ -struct nf_nat_range { - /* Set to OR of flags above. */ - unsigned int flags; - - /* Inclusive: network order. */ - __be32 min_ip, max_ip; - - /* Inclusive: network order */ - union nf_conntrack_man_proto min, max; -}; - -/* For backwards compat: don't use in modern code. */ -struct nf_nat_multi_range_compat { - unsigned int rangesize; /* Must be 1. */ - - /* hangs off end. */ - struct nf_nat_range range[1]; -}; - #include #include #include -- cgit v0.10.2 From ad542ced254f1c8560260e209f0f0d69dbae49e4 Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczynski Date: Tue, 18 Oct 2011 20:59:49 +0100 Subject: ipvs: Remove unused variable "cs" from ip_vs_leave function. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to address the following warning during compilation time: net/netfilter/ipvs/ip_vs_core.c: In function ‘ip_vs_leave’: net/netfilter/ipvs/ip_vs_core.c:532: warning: unused variable ‘cs’ This variable is indeed no longer in use. Signed-off-by: Krzysztof Wilczynski Signed-off-by: Simon Horman diff --git a/net/netfilter/ipvs/ip_vs_core.c b/net/netfilter/ipvs/ip_vs_core.c index 46a8130..093cc32 100644 --- a/net/netfilter/ipvs/ip_vs_core.c +++ b/net/netfilter/ipvs/ip_vs_core.c @@ -529,7 +529,7 @@ int ip_vs_leave(struct ip_vs_service *svc, struct sk_buff *skb, a cache_bypass connection entry */ ipvs = net_ipvs(net); if (ipvs->sysctl_cache_bypass && svc->fwmark && unicast) { - int ret, cs; + int ret; struct ip_vs_conn *cp; unsigned int flags = (svc->flags & IP_VS_SVC_F_ONEPACKET && iph.protocol == IPPROTO_UDP)? -- cgit v0.10.2 From e23ebf0fa9e1548c94d8277e393be97ba48faa06 Mon Sep 17 00:00:00 2001 From: Krzysztof Wilczynski Date: Thu, 20 Oct 2011 13:18:04 +0100 Subject: ipvs: Fix compilation error in ip_vs.h for ip_vs_confirm_conntrack function. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit This is to address the following error during the compilation: In file included from kernel/sysctl_binary.c:6: include/net/ip_vs.h:1406: error: expected identifier or ‘(’ before ‘{’ token make[1]: *** [kernel/sysctl_binary.o] Error 1 make[1]: *** Waiting for unfinished jobs.... That manifests itself when CONFIG_IP_VS_NFCT is undefined in .config file. Signed-off-by: Krzysztof Wilczynski Signed-off-by: Simon Horman diff --git a/include/net/ip_vs.h b/include/net/ip_vs.h index a6b8b47..05b08c9 100644 --- a/include/net/ip_vs.h +++ b/include/net/ip_vs.h @@ -1396,7 +1396,7 @@ static inline void ip_vs_update_conntrack(struct sk_buff *skb, { } -static inline int ip_vs_confirm_conntrack(struct sk_buff *skb); +static inline int ip_vs_confirm_conntrack(struct sk_buff *skb) { return NF_ACCEPT; } -- cgit v0.10.2 From 2dad81adf2c49aa9f8bb7e7c48dff9261bd58396 Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Wed, 19 Oct 2011 13:23:06 +0200 Subject: netfilter: ipv6: fix afinfo->route refcnt leak on error Several callers (h323 conntrack, xt_addrtype) assume that the returned **dst only needs to be released if the function returns 0. This is true for the ipv4 implementation, but not for the ipv6 one. Instead of changing the users, change the ipv6 implementation to behave like the ipv4 version by only providing the dst_entry result in the success case. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso diff --git a/net/ipv6/netfilter.c b/net/ipv6/netfilter.c index 30fcee4..8992cf6 100644 --- a/net/ipv6/netfilter.c +++ b/net/ipv6/netfilter.c @@ -100,9 +100,16 @@ static int nf_ip6_route(struct net *net, struct dst_entry **dst, .pinet6 = (struct ipv6_pinfo *) &fake_pinfo, }; const void *sk = strict ? &fake_sk : NULL; - - *dst = ip6_route_output(net, sk, &fl->u.ip6); - return (*dst)->error; + struct dst_entry *result; + int err; + + result = ip6_route_output(net, sk, &fl->u.ip6); + err = result->error; + if (err) + dst_release(result); + else + *dst = result; + return err; } __sum16 nf_ip6_checksum(struct sk_buff *skb, unsigned int hook, -- cgit v0.10.2 From 0e05e192c0ff706ee2a12eb65074085e3967d862 Mon Sep 17 00:00:00 2001 From: Pablo Neira Ayuso Date: Tue, 1 Nov 2011 09:44:56 +0100 Subject: MAINTAINERS: update netfilter maintainers Marc Boucher, James Morris and Rusty Russell were crucial in the early netfilter days. We thank them all! However, they are not actively maintaining netfilter anymore. This patch adds myself as netfilter maintainer. Signed-off-by: Pablo Neira Ayuso diff --git a/MAINTAINERS b/MAINTAINERS index 4befa12..8edf72b 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -4452,11 +4452,9 @@ F: Documentation/networking/vxge.txt F: drivers/net/ethernet/neterion/ NETFILTER/IPTABLES/IPCHAINS -P: Rusty Russell -P: Marc Boucher -P: James Morris P: Harald Welte P: Jozsef Kadlecsik +M: Pablo Neira Ayuso M: Patrick McHardy L: netfilter-devel@vger.kernel.org L: netfilter@vger.kernel.org -- cgit v0.10.2 From 563e12326473cb5d6cce0a4dca32509fe753eb8d Mon Sep 17 00:00:00 2001 From: Florian Westphal Date: Mon, 31 Oct 2011 12:20:16 +0100 Subject: netfilter: do not propagate nf_queue errors in nf_hook_slow commit f15850861860636c905b33a9a5be3dcbc2b0d56a (netfilter: nfnetlink_queue: return error number to caller) erronously assigns the return value of nf_queue() to the "ret" value. This can cause bogus return values if we encounter QUEUE verdict when bypassing is enabled, the listener does not exist and the next hook returns NF_STOLEN. In this case nf_hook_slow returned -ESRCH instead of 0. Signed-off-by: Florian Westphal Signed-off-by: Pablo Neira Ayuso diff --git a/net/netfilter/core.c b/net/netfilter/core.c index 3346829..afca6c7 100644 --- a/net/netfilter/core.c +++ b/net/netfilter/core.c @@ -180,17 +180,16 @@ next_hook: if (ret == 0) ret = -EPERM; } else if ((verdict & NF_VERDICT_MASK) == NF_QUEUE) { - ret = nf_queue(skb, elem, pf, hook, indev, outdev, okfn, - verdict >> NF_VERDICT_QBITS); - if (ret < 0) { - if (ret == -ECANCELED) + int err = nf_queue(skb, elem, pf, hook, indev, outdev, okfn, + verdict >> NF_VERDICT_QBITS); + if (err < 0) { + if (err == -ECANCELED) goto next_hook; - if (ret == -ESRCH && + if (err == -ESRCH && (verdict & NF_VERDICT_FLAG_QUEUE_BYPASS)) goto next_hook; kfree_skb(skb); } - ret = 0; } rcu_read_unlock(); return ret; -- cgit v0.10.2 From 045f7b3b0005bf30ad8d664c7651d816e2650cd2 Mon Sep 17 00:00:00 2001 From: "David S. Miller" Date: Tue, 1 Nov 2011 17:45:55 -0400 Subject: neigh: Kill bogus SMP protected debugging message. Whatever situations make this state legitimate when SMP also would be legitimate when !SMP and f.e. preemption is enabled. This is dubious enough that we should just delete it entirely. If we want to add debugging for neigh timer races, better more thorough mechanisms are needed. Signed-off-by: David S. Miller diff --git a/net/core/neighbour.c b/net/core/neighbour.c index 909ecb3..039d51e 100644 --- a/net/core/neighbour.c +++ b/net/core/neighbour.c @@ -872,12 +872,8 @@ static void neigh_timer_handler(unsigned long arg) now = jiffies; next = now + HZ; - if (!(state & NUD_IN_TIMER)) { -#ifndef CONFIG_SMP - printk(KERN_WARNING "neigh: timer & !nud_in_timer\n"); -#endif + if (!(state & NUD_IN_TIMER)) goto out; - } if (state & NUD_REACHABLE) { if (time_before_eq(now, -- cgit v0.10.2 From deede2fabe24e00bd7e246eb81cd5767dc6fcfc7 Mon Sep 17 00:00:00 2001 From: Matthijs Kooijman Date: Mon, 31 Oct 2011 04:53:13 +0000 Subject: vlan: Don't propagate flag changes on down interfaces. When (de)configuring a vlan interface, the IFF_ALLMULTI ans IFF_PROMISC flags are cleared or set on the underlying interface. So, if these flags are changed on a vlan interface that is not up, the flags underlying interface might be set or cleared twice. Only propagating flag changes when a device is up makes sure this does not happen. It also makes sure that an underlying device is not set to promiscuous or allmulti mode for a vlan device that is down. Signed-off-by: Matthijs Kooijman Signed-off-by: David S. Miller diff --git a/net/8021q/vlan_dev.c b/net/8021q/vlan_dev.c index c8cf939..bc25286 100644 --- a/net/8021q/vlan_dev.c +++ b/net/8021q/vlan_dev.c @@ -470,10 +470,12 @@ static void vlan_dev_change_rx_flags(struct net_device *dev, int change) { struct net_device *real_dev = vlan_dev_info(dev)->real_dev; - if (change & IFF_ALLMULTI) - dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1); - if (change & IFF_PROMISC) - dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1); + if (dev->flags & IFF_UP) { + if (change & IFF_ALLMULTI) + dev_set_allmulti(real_dev, dev->flags & IFF_ALLMULTI ? 1 : -1); + if (change & IFF_PROMISC) + dev_set_promiscuity(real_dev, dev->flags & IFF_PROMISC ? 1 : -1); + } } static void vlan_dev_set_rx_mode(struct net_device *vlan_dev) -- cgit v0.10.2 From 98f41f694f46085fda475cdee8cc0b6d2c5e6f1f Mon Sep 17 00:00:00 2001 From: Weiping Pan Date: Mon, 31 Oct 2011 17:20:48 +0000 Subject: bonding:update speed/duplex for NETDEV_CHANGE Zheng Liang(lzheng@redhat.com) found a bug that if we config bonding with arp monitor, sometimes bonding driver cannot get the speed and duplex from its slaves, it will assume them to be 100Mb/sec and Full, please see /proc/net/bonding/bond0. But there is no such problem when uses miimon. (Take igb for example) I find that the reason is that after dev_open() in bond_enslave(), bond_update_speed_duplex() will call igb_get_settings() , but in that function, it runs ethtool_cmd_speed_set(ecmd, -1); ecmd->duplex = -1; because igb get an error value of status. So even dev_open() is called, but the device is not really ready to get its settings. Maybe it is safe for us to call igb_get_settings() only after this message shows up, that is "igb: p4p1 NIC Link is Up 1000 Mbps Full Duplex, Flow Control: RX". So I prefer to update the speed and duplex for a slave when reseices NETDEV_CHANGE/NETDEV_UP event. Changelog V2: 1 remove the "fake 100/Full" logic in bond_update_speed_duplex(), set speed and duplex to -1 when it gets error value of speed and duplex. 2 delete the warning in bond_enslave() if bond_update_speed_duplex() returns error. 3 make bond_info_show_slave() handle bad values of speed and duplex. Signed-off-by: Weiping Pan Signed-off-by: David S. Miller diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c index c34cc1e..b2b9109 100644 --- a/drivers/net/bonding/bond_main.c +++ b/drivers/net/bonding/bond_main.c @@ -550,7 +550,7 @@ down: /* * Get link speed and duplex from the slave's base driver * using ethtool. If for some reason the call fails or the - * values are invalid, fake speed and duplex to 100/Full + * values are invalid, set speed and duplex to -1, * and return error. */ static int bond_update_speed_duplex(struct slave *slave) @@ -560,9 +560,8 @@ static int bond_update_speed_duplex(struct slave *slave) u32 slave_speed; int res; - /* Fake speed and duplex */ - slave->speed = SPEED_100; - slave->duplex = DUPLEX_FULL; + slave->speed = -1; + slave->duplex = -1; res = __ethtool_get_settings(slave_dev, &ecmd); if (res < 0) @@ -1751,16 +1750,7 @@ int bond_enslave(struct net_device *bond_dev, struct net_device *slave_dev) new_slave->link = BOND_LINK_DOWN; } - if (bond_update_speed_duplex(new_slave) && - (new_slave->link != BOND_LINK_DOWN)) { - pr_warning("%s: Warning: failed to get speed and duplex from %s, assumed to be 100Mb/sec and Full.\n", - bond_dev->name, new_slave->dev->name); - - if (bond->params.mode == BOND_MODE_8023AD) { - pr_warning("%s: Warning: Operation of 802.3ad mode requires ETHTOOL support in base driver for proper aggregator selection.\n", - bond_dev->name); - } - } + bond_update_speed_duplex(new_slave); if (USES_PRIMARY(bond->params.mode) && bond->params.primary[0]) { /* if there is a primary slave, remember it */ @@ -3220,6 +3210,7 @@ static int bond_slave_netdev_event(unsigned long event, { struct net_device *bond_dev = slave_dev->master; struct bonding *bond = netdev_priv(bond_dev); + struct slave *slave = NULL; switch (event) { case NETDEV_UNREGISTER: @@ -3230,20 +3221,16 @@ static int bond_slave_netdev_event(unsigned long event, bond_release(bond_dev, slave_dev); } break; + case NETDEV_UP: case NETDEV_CHANGE: - if (bond->params.mode == BOND_MODE_8023AD || bond_is_lb(bond)) { - struct slave *slave; + slave = bond_get_slave_by_dev(bond, slave_dev); + if (slave) { + u32 old_speed = slave->speed; + u8 old_duplex = slave->duplex; - slave = bond_get_slave_by_dev(bond, slave_dev); - if (slave) { - u32 old_speed = slave->speed; - u8 old_duplex = slave->duplex; - - bond_update_speed_duplex(slave); - - if (bond_is_lb(bond)) - break; + bond_update_speed_duplex(slave); + if (bond->params.mode == BOND_MODE_8023AD) { if (old_speed != slave->speed) bond_3ad_adapter_speed_changed(slave); if (old_duplex != slave->duplex) diff --git a/drivers/net/bonding/bond_procfs.c b/drivers/net/bonding/bond_procfs.c index 95de93b..d2ff52e 100644 --- a/drivers/net/bonding/bond_procfs.c +++ b/drivers/net/bonding/bond_procfs.c @@ -157,8 +157,16 @@ static void bond_info_show_slave(struct seq_file *seq, seq_printf(seq, "\nSlave Interface: %s\n", slave->dev->name); seq_printf(seq, "MII Status: %s\n", (slave->link == BOND_LINK_UP) ? "up" : "down"); - seq_printf(seq, "Speed: %d Mbps\n", slave->speed); - seq_printf(seq, "Duplex: %s\n", slave->duplex ? "full" : "half"); + if (slave->speed == -1) + seq_printf(seq, "Speed: %s\n", "Unknown"); + else + seq_printf(seq, "Speed: %d Mbps\n", slave->speed); + + if (slave->duplex == -1) + seq_printf(seq, "Duplex: %s\n", "Unknown"); + else + seq_printf(seq, "Duplex: %s\n", slave->duplex ? "full" : "half"); + seq_printf(seq, "Link Failure Count: %u\n", slave->link_failure_count); -- cgit v0.10.2 From 73cb88ecb950ee67906d02354f781ea293bcf895 Mon Sep 17 00:00:00 2001 From: Arjan van de Ven Date: Sun, 30 Oct 2011 06:46:30 +0000 Subject: net: make the tcp and udp file_operations for the /proc stuff const the tcp and udp code creates a set of struct file_operations at runtime while it can also be done at compile time, with the added benefit of then having these file operations be const. the trickiest part was to get the "THIS_MODULE" reference right; the naive method of declaring a struct in the place of registration would not work for this reason. Signed-off-by: Arjan van de Ven Signed-off-by: David S. Miller diff --git a/include/net/tcp.h b/include/net/tcp.h index e147f42..bb18c4d 100644 --- a/include/net/tcp.h +++ b/include/net/tcp.h @@ -1403,11 +1403,13 @@ enum tcp_seq_states { TCP_SEQ_STATE_TIME_WAIT, }; +int tcp_seq_open(struct inode *inode, struct file *file); + struct tcp_seq_afinfo { - char *name; - sa_family_t family; - struct file_operations seq_fops; - struct seq_operations seq_ops; + char *name; + sa_family_t family; + const struct file_operations *seq_fops; + struct seq_operations seq_ops; }; struct tcp_iter_state { diff --git a/include/net/udp.h b/include/net/udp.h index 67ea6fc..3b285f4 100644 --- a/include/net/udp.h +++ b/include/net/udp.h @@ -230,12 +230,14 @@ extern struct sock *udp6_lib_lookup(struct net *net, const struct in6_addr *sadd #endif /* /proc */ +int udp_seq_open(struct inode *inode, struct file *file); + struct udp_seq_afinfo { - char *name; - sa_family_t family; - struct udp_table *udp_table; - struct file_operations seq_fops; - struct seq_operations seq_ops; + char *name; + sa_family_t family; + struct udp_table *udp_table; + const struct file_operations *seq_fops; + struct seq_operations seq_ops; }; struct udp_iter_state { diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 0ea10ee..939c55e 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -2339,7 +2339,7 @@ static void tcp_seq_stop(struct seq_file *seq, void *v) } } -static int tcp_seq_open(struct inode *inode, struct file *file) +int tcp_seq_open(struct inode *inode, struct file *file) { struct tcp_seq_afinfo *afinfo = PDE(inode)->data; struct tcp_iter_state *s; @@ -2355,23 +2355,19 @@ static int tcp_seq_open(struct inode *inode, struct file *file) s->last_pos = 0; return 0; } +EXPORT_SYMBOL(tcp_seq_open); int tcp_proc_register(struct net *net, struct tcp_seq_afinfo *afinfo) { int rc = 0; struct proc_dir_entry *p; - afinfo->seq_fops.open = tcp_seq_open; - afinfo->seq_fops.read = seq_read; - afinfo->seq_fops.llseek = seq_lseek; - afinfo->seq_fops.release = seq_release_net; - afinfo->seq_ops.start = tcp_seq_start; afinfo->seq_ops.next = tcp_seq_next; afinfo->seq_ops.stop = tcp_seq_stop; p = proc_create_data(afinfo->name, S_IRUGO, net->proc_net, - &afinfo->seq_fops, afinfo); + afinfo->seq_fops, afinfo); if (!p) rc = -ENOMEM; return rc; @@ -2520,12 +2516,18 @@ out: return 0; } +static const struct file_operations tcp_afinfo_seq_fops = { + .owner = THIS_MODULE, + .open = tcp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_net +}; + static struct tcp_seq_afinfo tcp4_seq_afinfo = { .name = "tcp", .family = AF_INET, - .seq_fops = { - .owner = THIS_MODULE, - }, + .seq_fops = &tcp_afinfo_seq_fops, .seq_ops = { .show = tcp4_seq_show, }, diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index ebaa96b..131d8a7 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -2037,7 +2037,7 @@ static void udp_seq_stop(struct seq_file *seq, void *v) spin_unlock_bh(&state->udp_table->hash[state->bucket].lock); } -static int udp_seq_open(struct inode *inode, struct file *file) +int udp_seq_open(struct inode *inode, struct file *file) { struct udp_seq_afinfo *afinfo = PDE(inode)->data; struct udp_iter_state *s; @@ -2053,6 +2053,7 @@ static int udp_seq_open(struct inode *inode, struct file *file) s->udp_table = afinfo->udp_table; return err; } +EXPORT_SYMBOL(udp_seq_open); /* ------------------------------------------------------------------------ */ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) @@ -2060,17 +2061,12 @@ int udp_proc_register(struct net *net, struct udp_seq_afinfo *afinfo) struct proc_dir_entry *p; int rc = 0; - afinfo->seq_fops.open = udp_seq_open; - afinfo->seq_fops.read = seq_read; - afinfo->seq_fops.llseek = seq_lseek; - afinfo->seq_fops.release = seq_release_net; - afinfo->seq_ops.start = udp_seq_start; afinfo->seq_ops.next = udp_seq_next; afinfo->seq_ops.stop = udp_seq_stop; p = proc_create_data(afinfo->name, S_IRUGO, net->proc_net, - &afinfo->seq_fops, afinfo); + afinfo->seq_fops, afinfo); if (!p) rc = -ENOMEM; return rc; @@ -2120,14 +2116,20 @@ int udp4_seq_show(struct seq_file *seq, void *v) return 0; } +static const struct file_operations udp_afinfo_seq_fops = { + .owner = THIS_MODULE, + .open = udp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_net +}; + /* ------------------------------------------------------------------------ */ static struct udp_seq_afinfo udp4_seq_afinfo = { .name = "udp", .family = AF_INET, .udp_table = &udp_table, - .seq_fops = { - .owner = THIS_MODULE, - }, + .seq_fops = &udp_afinfo_seq_fops, .seq_ops = { .show = udp4_seq_show, }, diff --git a/net/ipv4/udplite.c b/net/ipv4/udplite.c index aee9963..08383eb 100644 --- a/net/ipv4/udplite.c +++ b/net/ipv4/udplite.c @@ -71,13 +71,20 @@ static struct inet_protosw udplite4_protosw = { }; #ifdef CONFIG_PROC_FS + +static const struct file_operations udplite_afinfo_seq_fops = { + .owner = THIS_MODULE, + .open = udp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_net +}; + static struct udp_seq_afinfo udplite4_seq_afinfo = { .name = "udplite", .family = AF_INET, .udp_table = &udplite_table, - .seq_fops = { - .owner = THIS_MODULE, - }, + .seq_fops = &udplite_afinfo_seq_fops, .seq_ops = { .show = udp4_seq_show, }, diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c index 10b2b31..36131d1 100644 --- a/net/ipv6/tcp_ipv6.c +++ b/net/ipv6/tcp_ipv6.c @@ -2161,12 +2161,18 @@ out: return 0; } +static const struct file_operations tcp6_afinfo_seq_fops = { + .owner = THIS_MODULE, + .open = tcp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_net +}; + static struct tcp_seq_afinfo tcp6_seq_afinfo = { .name = "tcp6", .family = AF_INET6, - .seq_fops = { - .owner = THIS_MODULE, - }, + .seq_fops = &tcp6_afinfo_seq_fops, .seq_ops = { .show = tcp6_seq_show, }, diff --git a/net/ipv6/udp.c b/net/ipv6/udp.c index f4ca0a5..846f4757 100644 --- a/net/ipv6/udp.c +++ b/net/ipv6/udp.c @@ -1424,13 +1424,19 @@ int udp6_seq_show(struct seq_file *seq, void *v) return 0; } +static const struct file_operations udp6_afinfo_seq_fops = { + .owner = THIS_MODULE, + .open = udp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_net +}; + static struct udp_seq_afinfo udp6_seq_afinfo = { .name = "udp6", .family = AF_INET6, .udp_table = &udp_table, - .seq_fops = { - .owner = THIS_MODULE, - }, + .seq_fops = &udp6_afinfo_seq_fops, .seq_ops = { .show = udp6_seq_show, }, diff --git a/net/ipv6/udplite.c b/net/ipv6/udplite.c index 986c4de..8889aa2 100644 --- a/net/ipv6/udplite.c +++ b/net/ipv6/udplite.c @@ -93,13 +93,20 @@ void udplitev6_exit(void) } #ifdef CONFIG_PROC_FS + +static const struct file_operations udplite6_afinfo_seq_fops = { + .owner = THIS_MODULE, + .open = udp_seq_open, + .read = seq_read, + .llseek = seq_lseek, + .release = seq_release_net +}; + static struct udp_seq_afinfo udplite6_seq_afinfo = { .name = "udplite6", .family = AF_INET6, .udp_table = &udplite_table, - .seq_fops = { - .owner = THIS_MODULE, - }, + .seq_fops = &udplite6_afinfo_seq_fops, .seq_ops = { .show = udp6_seq_show, }, -- cgit v0.10.2 From 048ca16935fdfbe17d1593e022eef4713c70c7e2 Mon Sep 17 00:00:00 2001 From: Paul Bolle Date: Sun, 30 Oct 2011 02:00:44 +0000 Subject: isdn: hisax: Fix typo 'HISAX_DE_AOC' That should probably be 'CONFIG_DE_AOC'. Signed-off-by: Paul Bolle Signed-off-by: David S. Miller diff --git a/drivers/isdn/hisax/l3dss1.c b/drivers/isdn/hisax/l3dss1.c index b0d9ab1..6a8acf6 100644 --- a/drivers/isdn/hisax/l3dss1.c +++ b/drivers/isdn/hisax/l3dss1.c @@ -353,7 +353,7 @@ l3dss1_parse_facility(struct PStack *st, struct l3_process *pc, { l3dss1_dummy_invoke(st, cr, id, ident, p, nlen); return; } -#ifdef HISAX_DE_AOC +#ifdef CONFIG_DE_AOC { #define FOO1(s,a,b) \ @@ -422,9 +422,9 @@ l3dss1_parse_facility(struct PStack *st, struct l3_process *pc, #undef FOO1 } -#else /* not HISAX_DE_AOC */ +#else /* not CONFIG_DE_AOC */ l3_debug(st, "invoke break"); -#endif /* not HISAX_DE_AOC */ +#endif /* not CONFIG_DE_AOC */ break; case 2: /* return result */ /* if no process available handle separately */ -- cgit v0.10.2 From 1b6b7172d0ee37528762bddb83acb56cb38ffac2 Mon Sep 17 00:00:00 2001 From: Cesar Eduardo Barros Date: Tue, 25 Oct 2011 12:32:24 +0000 Subject: net/ethernet: sc92031 is not Realtek While the SC92031 could be found on fake "Realtek" NICs, it has no relationship to Realtek, and is actually from Silan. Create a new subdirectory for silan and move sc92031 there. Signed-off-by: Cesar Eduardo Barros Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/Kconfig b/drivers/net/ethernet/Kconfig index 6dff5a0..597f4d4 100644 --- a/drivers/net/ethernet/Kconfig +++ b/drivers/net/ethernet/Kconfig @@ -159,6 +159,7 @@ config S6GMAC will be called s6gmac. source "drivers/net/ethernet/seeq/Kconfig" +source "drivers/net/ethernet/silan/Kconfig" source "drivers/net/ethernet/sis/Kconfig" source "drivers/net/ethernet/sfc/Kconfig" source "drivers/net/ethernet/sgi/Kconfig" diff --git a/drivers/net/ethernet/Makefile b/drivers/net/ethernet/Makefile index c53ad3a..be5dde0 100644 --- a/drivers/net/ethernet/Makefile +++ b/drivers/net/ethernet/Makefile @@ -58,6 +58,7 @@ obj-$(CONFIG_SH_ETH) += renesas/ obj-$(CONFIG_NET_VENDOR_RDC) += rdc/ obj-$(CONFIG_S6GMAC) += s6gmac.o obj-$(CONFIG_NET_VENDOR_SEEQ) += seeq/ +obj-$(CONFIG_NET_VENDOR_SILAN) += silan/ obj-$(CONFIG_NET_VENDOR_SIS) += sis/ obj-$(CONFIG_SFC) += sfc/ obj-$(CONFIG_NET_VENDOR_SGI) += sgi/ diff --git a/drivers/net/ethernet/realtek/Kconfig b/drivers/net/ethernet/realtek/Kconfig index 84083ec..0578859 100644 --- a/drivers/net/ethernet/realtek/Kconfig +++ b/drivers/net/ethernet/realtek/Kconfig @@ -115,16 +115,4 @@ config R8169 To compile this driver as a module, choose M here: the module will be called r8169. This is recommended. -config SC92031 - tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)" - depends on PCI && EXPERIMENTAL - select CRC32 - ---help--- - This is a driver for the Fast Ethernet PCI network cards based on - the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you - have one of these, say Y here. - - To compile this driver as a module, choose M here: the module - will be called sc92031. This is recommended. - endif # NET_VENDOR_REALTEK diff --git a/drivers/net/ethernet/realtek/Makefile b/drivers/net/ethernet/realtek/Makefile index e48cfb6..71b1da3 100644 --- a/drivers/net/ethernet/realtek/Makefile +++ b/drivers/net/ethernet/realtek/Makefile @@ -6,4 +6,3 @@ obj-$(CONFIG_8139CP) += 8139cp.o obj-$(CONFIG_8139TOO) += 8139too.o obj-$(CONFIG_ATP) += atp.o obj-$(CONFIG_R8169) += r8169.o -obj-$(CONFIG_SC92031) += sc92031.o diff --git a/drivers/net/ethernet/realtek/sc92031.c b/drivers/net/ethernet/realtek/sc92031.c deleted file mode 100644 index a284d64..0000000 --- a/drivers/net/ethernet/realtek/sc92031.c +++ /dev/null @@ -1,1609 +0,0 @@ -/* Silan SC92031 PCI Fast Ethernet Adapter driver - * - * Based on vendor drivers: - * Silan Fast Ethernet Netcard Driver: - * MODULE_AUTHOR ("gaoyonghong"); - * MODULE_DESCRIPTION ("SILAN Fast Ethernet driver"); - * MODULE_LICENSE("GPL"); - * 8139D Fast Ethernet driver: - * (C) 2002 by gaoyonghong - * MODULE_AUTHOR ("gaoyonghong"); - * MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver"); - * MODULE_LICENSE("GPL"); - * Both are almost identical and seem to be based on pci-skeleton.c - * - * Rewritten for 2.6 by Cesar Eduardo Barros - * - * A datasheet for this chip can be found at - * http://www.silan.com.cn/english/product/pdf/SC92031AY.pdf - */ - -/* Note about set_mac_address: I don't know how to change the hardware - * matching, so you need to enable IFF_PROMISC when using it. - */ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include - -#define SC92031_NAME "sc92031" - -/* BAR 0 is MMIO, BAR 1 is PIO */ -#ifndef SC92031_USE_BAR -#define SC92031_USE_BAR 0 -#endif - -/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */ -static int multicast_filter_limit = 64; -module_param(multicast_filter_limit, int, 0); -MODULE_PARM_DESC(multicast_filter_limit, - "Maximum number of filtered multicast addresses"); - -static int media; -module_param(media, int, 0); -MODULE_PARM_DESC(media, "Media type (0x00 = autodetect," - " 0x01 = 10M half, 0x02 = 10M full," - " 0x04 = 100M half, 0x08 = 100M full)"); - -/* Size of the in-memory receive ring. */ -#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/ -#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) - -/* Number of Tx descriptor registers. */ -#define NUM_TX_DESC 4 - -/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/ -#define MAX_ETH_FRAME_SIZE 1536 - -/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ -#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE -#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC) - -/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ -#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */ - -/* Time in jiffies before concluding the transmitter is hung. */ -#define TX_TIMEOUT (4*HZ) - -#define SILAN_STATS_NUM 2 /* number of ETHTOOL_GSTATS */ - -/* media options */ -#define AUTOSELECT 0x00 -#define M10_HALF 0x01 -#define M10_FULL 0x02 -#define M100_HALF 0x04 -#define M100_FULL 0x08 - - /* Symbolic offsets to registers. */ -enum silan_registers { - Config0 = 0x00, // Config0 - Config1 = 0x04, // Config1 - RxBufWPtr = 0x08, // Rx buffer writer poiter - IntrStatus = 0x0C, // Interrupt status - IntrMask = 0x10, // Interrupt mask - RxbufAddr = 0x14, // Rx buffer start address - RxBufRPtr = 0x18, // Rx buffer read pointer - Txstatusall = 0x1C, // Transmit status of all descriptors - TxStatus0 = 0x20, // Transmit status (Four 32bit registers). - TxAddr0 = 0x30, // Tx descriptors (also four 32bit). - RxConfig = 0x40, // Rx configuration - MAC0 = 0x44, // Ethernet hardware address. - MAR0 = 0x4C, // Multicast filter. - RxStatus0 = 0x54, // Rx status - TxConfig = 0x5C, // Tx configuration - PhyCtrl = 0x60, // physical control - FlowCtrlConfig = 0x64, // flow control - Miicmd0 = 0x68, // Mii command0 register - Miicmd1 = 0x6C, // Mii command1 register - Miistatus = 0x70, // Mii status register - Timercnt = 0x74, // Timer counter register - TimerIntr = 0x78, // Timer interrupt register - PMConfig = 0x7C, // Power Manager configuration - CRC0 = 0x80, // Power Manager CRC ( Two 32bit regisers) - Wakeup0 = 0x88, // power Manager wakeup( Eight 64bit regiser) - LSBCRC0 = 0xC8, // power Manager LSBCRC(Two 32bit regiser) - TestD0 = 0xD0, - TestD4 = 0xD4, - TestD8 = 0xD8, -}; - -#define MII_JAB 16 -#define MII_OutputStatus 24 - -#define PHY_16_JAB_ENB 0x1000 -#define PHY_16_PORT_ENB 0x1 - -enum IntrStatusBits { - LinkFail = 0x80000000, - LinkOK = 0x40000000, - TimeOut = 0x20000000, - RxOverflow = 0x0040, - RxOK = 0x0020, - TxOK = 0x0001, - IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK, -}; - -enum TxStatusBits { - TxCarrierLost = 0x20000000, - TxAborted = 0x10000000, - TxOutOfWindow = 0x08000000, - TxNccShift = 22, - EarlyTxThresShift = 16, - TxStatOK = 0x8000, - TxUnderrun = 0x4000, - TxOwn = 0x2000, -}; - -enum RxStatusBits { - RxStatesOK = 0x80000, - RxBadAlign = 0x40000, - RxHugeFrame = 0x20000, - RxSmallFrame = 0x10000, - RxCRCOK = 0x8000, - RxCrlFrame = 0x4000, - Rx_Broadcast = 0x2000, - Rx_Multicast = 0x1000, - RxAddrMatch = 0x0800, - MiiErr = 0x0400, -}; - -enum RxConfigBits { - RxFullDx = 0x80000000, - RxEnb = 0x40000000, - RxSmall = 0x20000000, - RxHuge = 0x10000000, - RxErr = 0x08000000, - RxAllphys = 0x04000000, - RxMulticast = 0x02000000, - RxBroadcast = 0x01000000, - RxLoopBack = (1 << 23) | (1 << 22), - LowThresholdShift = 12, - HighThresholdShift = 2, -}; - -enum TxConfigBits { - TxFullDx = 0x80000000, - TxEnb = 0x40000000, - TxEnbPad = 0x20000000, - TxEnbHuge = 0x10000000, - TxEnbFCS = 0x08000000, - TxNoBackOff = 0x04000000, - TxEnbPrem = 0x02000000, - TxCareLostCrs = 0x1000000, - TxExdCollNum = 0xf00000, - TxDataRate = 0x80000, -}; - -enum PhyCtrlconfigbits { - PhyCtrlAne = 0x80000000, - PhyCtrlSpd100 = 0x40000000, - PhyCtrlSpd10 = 0x20000000, - PhyCtrlPhyBaseAddr = 0x1f000000, - PhyCtrlDux = 0x800000, - PhyCtrlReset = 0x400000, -}; - -enum FlowCtrlConfigBits { - FlowCtrlFullDX = 0x80000000, - FlowCtrlEnb = 0x40000000, -}; - -enum Config0Bits { - Cfg0_Reset = 0x80000000, - Cfg0_Anaoff = 0x40000000, - Cfg0_LDPS = 0x20000000, -}; - -enum Config1Bits { - Cfg1_EarlyRx = 1 << 31, - Cfg1_EarlyTx = 1 << 30, - - //rx buffer size - Cfg1_Rcv8K = 0x0, - Cfg1_Rcv16K = 0x1, - Cfg1_Rcv32K = 0x3, - Cfg1_Rcv64K = 0x7, - Cfg1_Rcv128K = 0xf, -}; - -enum MiiCmd0Bits { - Mii_Divider = 0x20000000, - Mii_WRITE = 0x400000, - Mii_READ = 0x200000, - Mii_SCAN = 0x100000, - Mii_Tamod = 0x80000, - Mii_Drvmod = 0x40000, - Mii_mdc = 0x20000, - Mii_mdoen = 0x10000, - Mii_mdo = 0x8000, - Mii_mdi = 0x4000, -}; - -enum MiiStatusBits { - Mii_StatusBusy = 0x80000000, -}; - -enum PMConfigBits { - PM_Enable = 1 << 31, - PM_LongWF = 1 << 30, - PM_Magic = 1 << 29, - PM_LANWake = 1 << 28, - PM_LWPTN = (1 << 27 | 1<< 26), - PM_LinkUp = 1 << 25, - PM_WakeUp = 1 << 24, -}; - -/* Locking rules: - * priv->lock protects most of the fields of priv and most of the - * hardware registers. It does not have to protect against softirqs - * between sc92031_disable_interrupts and sc92031_enable_interrupts; - * it also does not need to be used in ->open and ->stop while the - * device interrupts are off. - * Not having to protect against softirqs is very useful due to heavy - * use of mdelay() at _sc92031_reset. - * Functions prefixed with _sc92031_ must be called with the lock held; - * functions prefixed with sc92031_ must be called without the lock held. - * Use mmiowb() before unlocking if the hardware was written to. - */ - -/* Locking rules for the interrupt: - * - the interrupt and the tasklet never run at the same time - * - neither run between sc92031_disable_interrupts and - * sc92031_enable_interrupt - */ - -struct sc92031_priv { - spinlock_t lock; - /* iomap.h cookie */ - void __iomem *port_base; - /* pci device structure */ - struct pci_dev *pdev; - /* tasklet */ - struct tasklet_struct tasklet; - - /* CPU address of rx ring */ - void *rx_ring; - /* PCI address of rx ring */ - dma_addr_t rx_ring_dma_addr; - /* PCI address of rx ring read pointer */ - dma_addr_t rx_ring_tail; - - /* tx ring write index */ - unsigned tx_head; - /* tx ring read index */ - unsigned tx_tail; - /* CPU address of tx bounce buffer */ - void *tx_bufs; - /* PCI address of tx bounce buffer */ - dma_addr_t tx_bufs_dma_addr; - - /* copies of some hardware registers */ - u32 intr_status; - atomic_t intr_mask; - u32 rx_config; - u32 tx_config; - u32 pm_config; - - /* copy of some flags from dev->flags */ - unsigned int mc_flags; - - /* for ETHTOOL_GSTATS */ - u64 tx_timeouts; - u64 rx_loss; - - /* for dev->get_stats */ - long rx_value; -}; - -/* I don't know which registers can be safely read; however, I can guess - * MAC0 is one of them. */ -static inline void _sc92031_dummy_read(void __iomem *port_base) -{ - ioread32(port_base + MAC0); -} - -static u32 _sc92031_mii_wait(void __iomem *port_base) -{ - u32 mii_status; - - do { - udelay(10); - mii_status = ioread32(port_base + Miistatus); - } while (mii_status & Mii_StatusBusy); - - return mii_status; -} - -static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1) -{ - iowrite32(Mii_Divider, port_base + Miicmd0); - - _sc92031_mii_wait(port_base); - - iowrite32(cmd1, port_base + Miicmd1); - iowrite32(Mii_Divider | cmd0, port_base + Miicmd0); - - return _sc92031_mii_wait(port_base); -} - -static void _sc92031_mii_scan(void __iomem *port_base) -{ - _sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6); -} - -static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg) -{ - return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13; -} - -static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val) -{ - _sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11)); -} - -static void sc92031_disable_interrupts(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - - /* tell the tasklet/interrupt not to enable interrupts */ - atomic_set(&priv->intr_mask, 0); - wmb(); - - /* stop interrupts */ - iowrite32(0, port_base + IntrMask); - _sc92031_dummy_read(port_base); - mmiowb(); - - /* wait for any concurrent interrupt/tasklet to finish */ - synchronize_irq(dev->irq); - tasklet_disable(&priv->tasklet); -} - -static void sc92031_enable_interrupts(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - - tasklet_enable(&priv->tasklet); - - atomic_set(&priv->intr_mask, IntrBits); - wmb(); - - iowrite32(IntrBits, port_base + IntrMask); - mmiowb(); -} - -static void _sc92031_disable_tx_rx(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - - priv->rx_config &= ~RxEnb; - priv->tx_config &= ~TxEnb; - iowrite32(priv->rx_config, port_base + RxConfig); - iowrite32(priv->tx_config, port_base + TxConfig); -} - -static void _sc92031_enable_tx_rx(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - - priv->rx_config |= RxEnb; - priv->tx_config |= TxEnb; - iowrite32(priv->rx_config, port_base + RxConfig); - iowrite32(priv->tx_config, port_base + TxConfig); -} - -static void _sc92031_tx_clear(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - - while (priv->tx_head - priv->tx_tail > 0) { - priv->tx_tail++; - dev->stats.tx_dropped++; - } - priv->tx_head = priv->tx_tail = 0; -} - -static void _sc92031_set_mar(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - u32 mar0 = 0, mar1 = 0; - - if ((dev->flags & IFF_PROMISC) || - netdev_mc_count(dev) > multicast_filter_limit || - (dev->flags & IFF_ALLMULTI)) - mar0 = mar1 = 0xffffffff; - else if (dev->flags & IFF_MULTICAST) { - struct netdev_hw_addr *ha; - - netdev_for_each_mc_addr(ha, dev) { - u32 crc; - unsigned bit = 0; - - crc = ~ether_crc(ETH_ALEN, ha->addr); - crc >>= 24; - - if (crc & 0x01) bit |= 0x02; - if (crc & 0x02) bit |= 0x01; - if (crc & 0x10) bit |= 0x20; - if (crc & 0x20) bit |= 0x10; - if (crc & 0x40) bit |= 0x08; - if (crc & 0x80) bit |= 0x04; - - if (bit > 31) - mar0 |= 0x1 << (bit - 32); - else - mar1 |= 0x1 << bit; - } - } - - iowrite32(mar0, port_base + MAR0); - iowrite32(mar1, port_base + MAR0 + 4); -} - -static void _sc92031_set_rx_config(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - unsigned int old_mc_flags; - u32 rx_config_bits = 0; - - old_mc_flags = priv->mc_flags; - - if (dev->flags & IFF_PROMISC) - rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast - | RxMulticast | RxAllphys; - - if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST)) - rx_config_bits |= RxMulticast; - - if (dev->flags & IFF_BROADCAST) - rx_config_bits |= RxBroadcast; - - priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast - | RxMulticast | RxAllphys); - priv->rx_config |= rx_config_bits; - - priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI - | IFF_MULTICAST | IFF_BROADCAST); - - if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags) - iowrite32(priv->rx_config, port_base + RxConfig); -} - -static bool _sc92031_check_media(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - u16 bmsr; - - bmsr = _sc92031_mii_read(port_base, MII_BMSR); - rmb(); - if (bmsr & BMSR_LSTATUS) { - bool speed_100, duplex_full; - u32 flow_ctrl_config = 0; - u16 output_status = _sc92031_mii_read(port_base, - MII_OutputStatus); - _sc92031_mii_scan(port_base); - - speed_100 = output_status & 0x2; - duplex_full = output_status & 0x4; - - /* Initial Tx/Rx configuration */ - priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift); - priv->tx_config = 0x48800000; - - /* NOTE: vendor driver had dead code here to enable tx padding */ - - if (!speed_100) - priv->tx_config |= 0x80000; - - // configure rx mode - _sc92031_set_rx_config(dev); - - if (duplex_full) { - priv->rx_config |= RxFullDx; - priv->tx_config |= TxFullDx; - flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb; - } else { - priv->rx_config &= ~RxFullDx; - priv->tx_config &= ~TxFullDx; - } - - _sc92031_set_mar(dev); - _sc92031_set_rx_config(dev); - _sc92031_enable_tx_rx(dev); - iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig); - - netif_carrier_on(dev); - - if (printk_ratelimit()) - printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n", - dev->name, - speed_100 ? "100" : "10", - duplex_full ? "full" : "half"); - return true; - } else { - _sc92031_mii_scan(port_base); - - netif_carrier_off(dev); - - _sc92031_disable_tx_rx(dev); - - if (printk_ratelimit()) - printk(KERN_INFO "%s: link down\n", dev->name); - return false; - } -} - -static void _sc92031_phy_reset(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - u32 phy_ctrl; - - phy_ctrl = ioread32(port_base + PhyCtrl); - phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10); - phy_ctrl |= PhyCtrlAne | PhyCtrlReset; - - switch (media) { - default: - case AUTOSELECT: - phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10; - break; - case M10_HALF: - phy_ctrl |= PhyCtrlSpd10; - break; - case M10_FULL: - phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10; - break; - case M100_HALF: - phy_ctrl |= PhyCtrlSpd100; - break; - case M100_FULL: - phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100; - break; - } - - iowrite32(phy_ctrl, port_base + PhyCtrl); - mdelay(10); - - phy_ctrl &= ~PhyCtrlReset; - iowrite32(phy_ctrl, port_base + PhyCtrl); - mdelay(1); - - _sc92031_mii_write(port_base, MII_JAB, - PHY_16_JAB_ENB | PHY_16_PORT_ENB); - _sc92031_mii_scan(port_base); - - netif_carrier_off(dev); - netif_stop_queue(dev); -} - -static void _sc92031_reset(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - - /* disable PM */ - iowrite32(0, port_base + PMConfig); - - /* soft reset the chip */ - iowrite32(Cfg0_Reset, port_base + Config0); - mdelay(200); - - iowrite32(0, port_base + Config0); - mdelay(10); - - /* disable interrupts */ - iowrite32(0, port_base + IntrMask); - - /* clear multicast address */ - iowrite32(0, port_base + MAR0); - iowrite32(0, port_base + MAR0 + 4); - - /* init rx ring */ - iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr); - priv->rx_ring_tail = priv->rx_ring_dma_addr; - - /* init tx ring */ - _sc92031_tx_clear(dev); - - /* clear old register values */ - priv->intr_status = 0; - atomic_set(&priv->intr_mask, 0); - priv->rx_config = 0; - priv->tx_config = 0; - priv->mc_flags = 0; - - /* configure rx buffer size */ - /* NOTE: vendor driver had dead code here to enable early tx/rx */ - iowrite32(Cfg1_Rcv64K, port_base + Config1); - - _sc92031_phy_reset(dev); - _sc92031_check_media(dev); - - /* calculate rx fifo overflow */ - priv->rx_value = 0; - - /* enable PM */ - iowrite32(priv->pm_config, port_base + PMConfig); - - /* clear intr register */ - ioread32(port_base + IntrStatus); -} - -static void _sc92031_tx_tasklet(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - - unsigned old_tx_tail; - unsigned entry; - u32 tx_status; - - old_tx_tail = priv->tx_tail; - while (priv->tx_head - priv->tx_tail > 0) { - entry = priv->tx_tail % NUM_TX_DESC; - tx_status = ioread32(port_base + TxStatus0 + entry * 4); - - if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted))) - break; - - priv->tx_tail++; - - if (tx_status & TxStatOK) { - dev->stats.tx_bytes += tx_status & 0x1fff; - dev->stats.tx_packets++; - /* Note: TxCarrierLost is always asserted at 100mbps. */ - dev->stats.collisions += (tx_status >> 22) & 0xf; - } - - if (tx_status & (TxOutOfWindow | TxAborted)) { - dev->stats.tx_errors++; - - if (tx_status & TxAborted) - dev->stats.tx_aborted_errors++; - - if (tx_status & TxCarrierLost) - dev->stats.tx_carrier_errors++; - - if (tx_status & TxOutOfWindow) - dev->stats.tx_window_errors++; - } - - if (tx_status & TxUnderrun) - dev->stats.tx_fifo_errors++; - } - - if (priv->tx_tail != old_tx_tail) - if (netif_queue_stopped(dev)) - netif_wake_queue(dev); -} - -static void _sc92031_rx_tasklet_error(struct net_device *dev, - u32 rx_status, unsigned rx_size) -{ - if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) { - dev->stats.rx_errors++; - dev->stats.rx_length_errors++; - } - - if (!(rx_status & RxStatesOK)) { - dev->stats.rx_errors++; - - if (rx_status & (RxHugeFrame | RxSmallFrame)) - dev->stats.rx_length_errors++; - - if (rx_status & RxBadAlign) - dev->stats.rx_frame_errors++; - - if (!(rx_status & RxCRCOK)) - dev->stats.rx_crc_errors++; - } else { - struct sc92031_priv *priv = netdev_priv(dev); - priv->rx_loss++; - } -} - -static void _sc92031_rx_tasklet(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - - dma_addr_t rx_ring_head; - unsigned rx_len; - unsigned rx_ring_offset; - void *rx_ring = priv->rx_ring; - - rx_ring_head = ioread32(port_base + RxBufWPtr); - rmb(); - - /* rx_ring_head is only 17 bits in the RxBufWPtr register. - * we need to change it to 32 bits physical address - */ - rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1); - rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1); - if (rx_ring_head < priv->rx_ring_dma_addr) - rx_ring_head += RX_BUF_LEN; - - if (rx_ring_head >= priv->rx_ring_tail) - rx_len = rx_ring_head - priv->rx_ring_tail; - else - rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head); - - if (!rx_len) - return; - - if (unlikely(rx_len > RX_BUF_LEN)) { - if (printk_ratelimit()) - printk(KERN_ERR "%s: rx packets length > rx buffer\n", - dev->name); - return; - } - - rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN; - - while (rx_len) { - u32 rx_status; - unsigned rx_size, rx_size_align, pkt_size; - struct sk_buff *skb; - - rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset)); - rmb(); - - rx_size = rx_status >> 20; - rx_size_align = (rx_size + 3) & ~3; // for 4 bytes aligned - pkt_size = rx_size - 4; // Omit the four octet CRC from the length. - - rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN; - - if (unlikely(rx_status == 0 || - rx_size > (MAX_ETH_FRAME_SIZE + 4) || - rx_size < 16 || - !(rx_status & RxStatesOK))) { - _sc92031_rx_tasklet_error(dev, rx_status, rx_size); - break; - } - - if (unlikely(rx_size_align + 4 > rx_len)) { - if (printk_ratelimit()) - printk(KERN_ERR "%s: rx_len is too small\n", dev->name); - break; - } - - rx_len -= rx_size_align + 4; - - skb = netdev_alloc_skb_ip_align(dev, pkt_size); - if (unlikely(!skb)) { - if (printk_ratelimit()) - printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n", - dev->name, pkt_size); - goto next; - } - - if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) { - memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset), - rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset); - memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)), - rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset)); - } else { - memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size); - } - - skb->protocol = eth_type_trans(skb, dev); - netif_rx(skb); - - dev->stats.rx_bytes += pkt_size; - dev->stats.rx_packets++; - - if (rx_status & Rx_Multicast) - dev->stats.multicast++; - - next: - rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN; - } - mb(); - - priv->rx_ring_tail = rx_ring_head; - iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr); -} - -static void _sc92031_link_tasklet(struct net_device *dev) -{ - if (_sc92031_check_media(dev)) - netif_wake_queue(dev); - else { - netif_stop_queue(dev); - dev->stats.tx_carrier_errors++; - } -} - -static void sc92031_tasklet(unsigned long data) -{ - struct net_device *dev = (struct net_device *)data; - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - u32 intr_status, intr_mask; - - intr_status = priv->intr_status; - - spin_lock(&priv->lock); - - if (unlikely(!netif_running(dev))) - goto out; - - if (intr_status & TxOK) - _sc92031_tx_tasklet(dev); - - if (intr_status & RxOK) - _sc92031_rx_tasklet(dev); - - if (intr_status & RxOverflow) - dev->stats.rx_errors++; - - if (intr_status & TimeOut) { - dev->stats.rx_errors++; - dev->stats.rx_length_errors++; - } - - if (intr_status & (LinkFail | LinkOK)) - _sc92031_link_tasklet(dev); - -out: - intr_mask = atomic_read(&priv->intr_mask); - rmb(); - - iowrite32(intr_mask, port_base + IntrMask); - mmiowb(); - - spin_unlock(&priv->lock); -} - -static irqreturn_t sc92031_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - u32 intr_status, intr_mask; - - /* mask interrupts before clearing IntrStatus */ - iowrite32(0, port_base + IntrMask); - _sc92031_dummy_read(port_base); - - intr_status = ioread32(port_base + IntrStatus); - if (unlikely(intr_status == 0xffffffff)) - return IRQ_NONE; // hardware has gone missing - - intr_status &= IntrBits; - if (!intr_status) - goto out_none; - - priv->intr_status = intr_status; - tasklet_schedule(&priv->tasklet); - - return IRQ_HANDLED; - -out_none: - intr_mask = atomic_read(&priv->intr_mask); - rmb(); - - iowrite32(intr_mask, port_base + IntrMask); - mmiowb(); - - return IRQ_NONE; -} - -static struct net_device_stats *sc92031_get_stats(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - - // FIXME I do not understand what is this trying to do. - if (netif_running(dev)) { - int temp; - - spin_lock_bh(&priv->lock); - - /* Update the error count. */ - temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff; - - if (temp == 0xffff) { - priv->rx_value += temp; - dev->stats.rx_fifo_errors = priv->rx_value; - } else - dev->stats.rx_fifo_errors = temp + priv->rx_value; - - spin_unlock_bh(&priv->lock); - } - - return &dev->stats; -} - -static netdev_tx_t sc92031_start_xmit(struct sk_buff *skb, - struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - unsigned len; - unsigned entry; - u32 tx_status; - - if (unlikely(skb->len > TX_BUF_SIZE)) { - dev->stats.tx_dropped++; - goto out; - } - - spin_lock(&priv->lock); - - if (unlikely(!netif_carrier_ok(dev))) { - dev->stats.tx_dropped++; - goto out_unlock; - } - - BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC); - - entry = priv->tx_head++ % NUM_TX_DESC; - - skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE); - - len = skb->len; - if (len < ETH_ZLEN) { - memset(priv->tx_bufs + entry * TX_BUF_SIZE + len, - 0, ETH_ZLEN - len); - len = ETH_ZLEN; - } - - wmb(); - - if (len < 100) - tx_status = len; - else if (len < 300) - tx_status = 0x30000 | len; - else - tx_status = 0x50000 | len; - - iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE, - port_base + TxAddr0 + entry * 4); - iowrite32(tx_status, port_base + TxStatus0 + entry * 4); - mmiowb(); - - if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC) - netif_stop_queue(dev); - -out_unlock: - spin_unlock(&priv->lock); - -out: - dev_kfree_skb(skb); - - return NETDEV_TX_OK; -} - -static int sc92031_open(struct net_device *dev) -{ - int err; - struct sc92031_priv *priv = netdev_priv(dev); - struct pci_dev *pdev = priv->pdev; - - priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN, - &priv->rx_ring_dma_addr); - if (unlikely(!priv->rx_ring)) { - err = -ENOMEM; - goto out_alloc_rx_ring; - } - - priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN, - &priv->tx_bufs_dma_addr); - if (unlikely(!priv->tx_bufs)) { - err = -ENOMEM; - goto out_alloc_tx_bufs; - } - priv->tx_head = priv->tx_tail = 0; - - err = request_irq(pdev->irq, sc92031_interrupt, - IRQF_SHARED, dev->name, dev); - if (unlikely(err < 0)) - goto out_request_irq; - - priv->pm_config = 0; - - /* Interrupts already disabled by sc92031_stop or sc92031_probe */ - spin_lock_bh(&priv->lock); - - _sc92031_reset(dev); - mmiowb(); - - spin_unlock_bh(&priv->lock); - sc92031_enable_interrupts(dev); - - if (netif_carrier_ok(dev)) - netif_start_queue(dev); - else - netif_tx_disable(dev); - - return 0; - -out_request_irq: - pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs, - priv->tx_bufs_dma_addr); -out_alloc_tx_bufs: - pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring, - priv->rx_ring_dma_addr); -out_alloc_rx_ring: - return err; -} - -static int sc92031_stop(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - struct pci_dev *pdev = priv->pdev; - - netif_tx_disable(dev); - - /* Disable interrupts, stop Tx and Rx. */ - sc92031_disable_interrupts(dev); - - spin_lock_bh(&priv->lock); - - _sc92031_disable_tx_rx(dev); - _sc92031_tx_clear(dev); - mmiowb(); - - spin_unlock_bh(&priv->lock); - - free_irq(pdev->irq, dev); - pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs, - priv->tx_bufs_dma_addr); - pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring, - priv->rx_ring_dma_addr); - - return 0; -} - -static void sc92031_set_multicast_list(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - - spin_lock_bh(&priv->lock); - - _sc92031_set_mar(dev); - _sc92031_set_rx_config(dev); - mmiowb(); - - spin_unlock_bh(&priv->lock); -} - -static void sc92031_tx_timeout(struct net_device *dev) -{ - struct sc92031_priv *priv = netdev_priv(dev); - - /* Disable interrupts by clearing the interrupt mask.*/ - sc92031_disable_interrupts(dev); - - spin_lock(&priv->lock); - - priv->tx_timeouts++; - - _sc92031_reset(dev); - mmiowb(); - - spin_unlock(&priv->lock); - - /* enable interrupts */ - sc92031_enable_interrupts(dev); - - if (netif_carrier_ok(dev)) - netif_wake_queue(dev); -} - -#ifdef CONFIG_NET_POLL_CONTROLLER -static void sc92031_poll_controller(struct net_device *dev) -{ - disable_irq(dev->irq); - if (sc92031_interrupt(dev->irq, dev) != IRQ_NONE) - sc92031_tasklet((unsigned long)dev); - enable_irq(dev->irq); -} -#endif - -static int sc92031_ethtool_get_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - u8 phy_address; - u32 phy_ctrl; - u16 output_status; - - spin_lock_bh(&priv->lock); - - phy_address = ioread32(port_base + Miicmd1) >> 27; - phy_ctrl = ioread32(port_base + PhyCtrl); - - output_status = _sc92031_mii_read(port_base, MII_OutputStatus); - _sc92031_mii_scan(port_base); - mmiowb(); - - spin_unlock_bh(&priv->lock); - - cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full - | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full - | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII; - - cmd->advertising = ADVERTISED_TP | ADVERTISED_MII; - - if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10)) - == (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10)) - cmd->advertising |= ADVERTISED_Autoneg; - - if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10) - cmd->advertising |= ADVERTISED_10baseT_Half; - - if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux)) - == (PhyCtrlSpd10 | PhyCtrlDux)) - cmd->advertising |= ADVERTISED_10baseT_Full; - - if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100) - cmd->advertising |= ADVERTISED_100baseT_Half; - - if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux)) - == (PhyCtrlSpd100 | PhyCtrlDux)) - cmd->advertising |= ADVERTISED_100baseT_Full; - - if (phy_ctrl & PhyCtrlAne) - cmd->advertising |= ADVERTISED_Autoneg; - - ethtool_cmd_speed_set(cmd, - (output_status & 0x2) ? SPEED_100 : SPEED_10); - cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF; - cmd->port = PORT_MII; - cmd->phy_address = phy_address; - cmd->transceiver = XCVR_INTERNAL; - cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE; - - return 0; -} - -static int sc92031_ethtool_set_settings(struct net_device *dev, - struct ethtool_cmd *cmd) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - u32 speed = ethtool_cmd_speed(cmd); - u32 phy_ctrl; - u32 old_phy_ctrl; - - if (!(speed == SPEED_10 || speed == SPEED_100)) - return -EINVAL; - if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL)) - return -EINVAL; - if (!(cmd->port == PORT_MII)) - return -EINVAL; - if (!(cmd->phy_address == 0x1f)) - return -EINVAL; - if (!(cmd->transceiver == XCVR_INTERNAL)) - return -EINVAL; - if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE)) - return -EINVAL; - - if (cmd->autoneg == AUTONEG_ENABLE) { - if (!(cmd->advertising & (ADVERTISED_Autoneg - | ADVERTISED_100baseT_Full - | ADVERTISED_100baseT_Half - | ADVERTISED_10baseT_Full - | ADVERTISED_10baseT_Half))) - return -EINVAL; - - phy_ctrl = PhyCtrlAne; - - // FIXME: I'm not sure what the original code was trying to do - if (cmd->advertising & ADVERTISED_Autoneg) - phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10; - if (cmd->advertising & ADVERTISED_100baseT_Full) - phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100; - if (cmd->advertising & ADVERTISED_100baseT_Half) - phy_ctrl |= PhyCtrlSpd100; - if (cmd->advertising & ADVERTISED_10baseT_Full) - phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux; - if (cmd->advertising & ADVERTISED_10baseT_Half) - phy_ctrl |= PhyCtrlSpd10; - } else { - // FIXME: Whole branch guessed - phy_ctrl = 0; - - if (speed == SPEED_10) - phy_ctrl |= PhyCtrlSpd10; - else /* cmd->speed == SPEED_100 */ - phy_ctrl |= PhyCtrlSpd100; - - if (cmd->duplex == DUPLEX_FULL) - phy_ctrl |= PhyCtrlDux; - } - - spin_lock_bh(&priv->lock); - - old_phy_ctrl = ioread32(port_base + PhyCtrl); - phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux - | PhyCtrlSpd100 | PhyCtrlSpd10); - if (phy_ctrl != old_phy_ctrl) - iowrite32(phy_ctrl, port_base + PhyCtrl); - - spin_unlock_bh(&priv->lock); - - return 0; -} - -static void sc92031_ethtool_get_wol(struct net_device *dev, - struct ethtool_wolinfo *wolinfo) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - u32 pm_config; - - spin_lock_bh(&priv->lock); - pm_config = ioread32(port_base + PMConfig); - spin_unlock_bh(&priv->lock); - - // FIXME: Guessed - wolinfo->supported = WAKE_PHY | WAKE_MAGIC - | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; - wolinfo->wolopts = 0; - - if (pm_config & PM_LinkUp) - wolinfo->wolopts |= WAKE_PHY; - - if (pm_config & PM_Magic) - wolinfo->wolopts |= WAKE_MAGIC; - - if (pm_config & PM_WakeUp) - // FIXME: Guessed - wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; -} - -static int sc92031_ethtool_set_wol(struct net_device *dev, - struct ethtool_wolinfo *wolinfo) -{ - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - u32 pm_config; - - spin_lock_bh(&priv->lock); - - pm_config = ioread32(port_base + PMConfig) - & ~(PM_LinkUp | PM_Magic | PM_WakeUp); - - if (wolinfo->wolopts & WAKE_PHY) - pm_config |= PM_LinkUp; - - if (wolinfo->wolopts & WAKE_MAGIC) - pm_config |= PM_Magic; - - // FIXME: Guessed - if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)) - pm_config |= PM_WakeUp; - - priv->pm_config = pm_config; - iowrite32(pm_config, port_base + PMConfig); - mmiowb(); - - spin_unlock_bh(&priv->lock); - - return 0; -} - -static int sc92031_ethtool_nway_reset(struct net_device *dev) -{ - int err = 0; - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem *port_base = priv->port_base; - u16 bmcr; - - spin_lock_bh(&priv->lock); - - bmcr = _sc92031_mii_read(port_base, MII_BMCR); - if (!(bmcr & BMCR_ANENABLE)) { - err = -EINVAL; - goto out; - } - - _sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART); - -out: - _sc92031_mii_scan(port_base); - mmiowb(); - - spin_unlock_bh(&priv->lock); - - return err; -} - -static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = { - "tx_timeout", - "rx_loss", -}; - -static void sc92031_ethtool_get_strings(struct net_device *dev, - u32 stringset, u8 *data) -{ - if (stringset == ETH_SS_STATS) - memcpy(data, sc92031_ethtool_stats_strings, - SILAN_STATS_NUM * ETH_GSTRING_LEN); -} - -static int sc92031_ethtool_get_sset_count(struct net_device *dev, int sset) -{ - switch (sset) { - case ETH_SS_STATS: - return SILAN_STATS_NUM; - default: - return -EOPNOTSUPP; - } -} - -static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev, - struct ethtool_stats *stats, u64 *data) -{ - struct sc92031_priv *priv = netdev_priv(dev); - - spin_lock_bh(&priv->lock); - data[0] = priv->tx_timeouts; - data[1] = priv->rx_loss; - spin_unlock_bh(&priv->lock); -} - -static const struct ethtool_ops sc92031_ethtool_ops = { - .get_settings = sc92031_ethtool_get_settings, - .set_settings = sc92031_ethtool_set_settings, - .get_wol = sc92031_ethtool_get_wol, - .set_wol = sc92031_ethtool_set_wol, - .nway_reset = sc92031_ethtool_nway_reset, - .get_link = ethtool_op_get_link, - .get_strings = sc92031_ethtool_get_strings, - .get_sset_count = sc92031_ethtool_get_sset_count, - .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, -}; - - -static const struct net_device_ops sc92031_netdev_ops = { - .ndo_get_stats = sc92031_get_stats, - .ndo_start_xmit = sc92031_start_xmit, - .ndo_open = sc92031_open, - .ndo_stop = sc92031_stop, - .ndo_set_rx_mode = sc92031_set_multicast_list, - .ndo_change_mtu = eth_change_mtu, - .ndo_validate_addr = eth_validate_addr, - .ndo_set_mac_address = eth_mac_addr, - .ndo_tx_timeout = sc92031_tx_timeout, -#ifdef CONFIG_NET_POLL_CONTROLLER - .ndo_poll_controller = sc92031_poll_controller, -#endif -}; - -static int __devinit sc92031_probe(struct pci_dev *pdev, - const struct pci_device_id *id) -{ - int err; - void __iomem* port_base; - struct net_device *dev; - struct sc92031_priv *priv; - u32 mac0, mac1; - unsigned long base_addr; - - err = pci_enable_device(pdev); - if (unlikely(err < 0)) - goto out_enable_device; - - pci_set_master(pdev); - - err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); - if (unlikely(err < 0)) - goto out_set_dma_mask; - - err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); - if (unlikely(err < 0)) - goto out_set_dma_mask; - - err = pci_request_regions(pdev, SC92031_NAME); - if (unlikely(err < 0)) - goto out_request_regions; - - port_base = pci_iomap(pdev, SC92031_USE_BAR, 0); - if (unlikely(!port_base)) { - err = -EIO; - goto out_iomap; - } - - dev = alloc_etherdev(sizeof(struct sc92031_priv)); - if (unlikely(!dev)) { - err = -ENOMEM; - goto out_alloc_etherdev; - } - - pci_set_drvdata(pdev, dev); - SET_NETDEV_DEV(dev, &pdev->dev); - -#if SC92031_USE_BAR == 0 - dev->mem_start = pci_resource_start(pdev, SC92031_USE_BAR); - dev->mem_end = pci_resource_end(pdev, SC92031_USE_BAR); -#elif SC92031_USE_BAR == 1 - dev->base_addr = pci_resource_start(pdev, SC92031_USE_BAR); -#endif - dev->irq = pdev->irq; - - /* faked with skb_copy_and_csum_dev */ - dev->features = NETIF_F_SG | NETIF_F_HIGHDMA | - NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; - - dev->netdev_ops = &sc92031_netdev_ops; - dev->watchdog_timeo = TX_TIMEOUT; - dev->ethtool_ops = &sc92031_ethtool_ops; - - priv = netdev_priv(dev); - spin_lock_init(&priv->lock); - priv->port_base = port_base; - priv->pdev = pdev; - tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev); - /* Fudge tasklet count so the call to sc92031_enable_interrupts at - * sc92031_open will work correctly */ - tasklet_disable_nosync(&priv->tasklet); - - /* PCI PM Wakeup */ - iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig); - - mac0 = ioread32(port_base + MAC0); - mac1 = ioread32(port_base + MAC0 + 4); - dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24; - dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16; - dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8; - dev->dev_addr[3] = dev->perm_addr[3] = mac0; - dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8; - dev->dev_addr[5] = dev->perm_addr[5] = mac1; - - err = register_netdev(dev); - if (err < 0) - goto out_register_netdev; - -#if SC92031_USE_BAR == 0 - base_addr = dev->mem_start; -#elif SC92031_USE_BAR == 1 - base_addr = dev->base_addr; -#endif - printk(KERN_INFO "%s: SC92031 at 0x%lx, %pM, IRQ %d\n", dev->name, - base_addr, dev->dev_addr, dev->irq); - - return 0; - -out_register_netdev: - free_netdev(dev); -out_alloc_etherdev: - pci_iounmap(pdev, port_base); -out_iomap: - pci_release_regions(pdev); -out_request_regions: -out_set_dma_mask: - pci_disable_device(pdev); -out_enable_device: - return err; -} - -static void __devexit sc92031_remove(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct sc92031_priv *priv = netdev_priv(dev); - void __iomem* port_base = priv->port_base; - - unregister_netdev(dev); - free_netdev(dev); - pci_iounmap(pdev, port_base); - pci_release_regions(pdev); - pci_disable_device(pdev); -} - -static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct sc92031_priv *priv = netdev_priv(dev); - - pci_save_state(pdev); - - if (!netif_running(dev)) - goto out; - - netif_device_detach(dev); - - /* Disable interrupts, stop Tx and Rx. */ - sc92031_disable_interrupts(dev); - - spin_lock_bh(&priv->lock); - - _sc92031_disable_tx_rx(dev); - _sc92031_tx_clear(dev); - mmiowb(); - - spin_unlock_bh(&priv->lock); - -out: - pci_set_power_state(pdev, pci_choose_state(pdev, state)); - - return 0; -} - -static int sc92031_resume(struct pci_dev *pdev) -{ - struct net_device *dev = pci_get_drvdata(pdev); - struct sc92031_priv *priv = netdev_priv(dev); - - pci_restore_state(pdev); - pci_set_power_state(pdev, PCI_D0); - - if (!netif_running(dev)) - goto out; - - /* Interrupts already disabled by sc92031_suspend */ - spin_lock_bh(&priv->lock); - - _sc92031_reset(dev); - mmiowb(); - - spin_unlock_bh(&priv->lock); - sc92031_enable_interrupts(dev); - - netif_device_attach(dev); - - if (netif_carrier_ok(dev)) - netif_wake_queue(dev); - else - netif_tx_disable(dev); - -out: - return 0; -} - -static DEFINE_PCI_DEVICE_TABLE(sc92031_pci_device_id_table) = { - { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x2031) }, - { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x8139) }, - { PCI_DEVICE(0x1088, 0x2031) }, - { 0, } -}; -MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table); - -static struct pci_driver sc92031_pci_driver = { - .name = SC92031_NAME, - .id_table = sc92031_pci_device_id_table, - .probe = sc92031_probe, - .remove = __devexit_p(sc92031_remove), - .suspend = sc92031_suspend, - .resume = sc92031_resume, -}; - -static int __init sc92031_init(void) -{ - return pci_register_driver(&sc92031_pci_driver); -} - -static void __exit sc92031_exit(void) -{ - pci_unregister_driver(&sc92031_pci_driver); -} - -module_init(sc92031_init); -module_exit(sc92031_exit); - -MODULE_LICENSE("GPL"); -MODULE_AUTHOR("Cesar Eduardo Barros "); -MODULE_DESCRIPTION("Silan SC92031 PCI Fast Ethernet Adapter driver"); diff --git a/drivers/net/ethernet/silan/Kconfig b/drivers/net/ethernet/silan/Kconfig new file mode 100644 index 0000000..ae1ce17 --- /dev/null +++ b/drivers/net/ethernet/silan/Kconfig @@ -0,0 +1,33 @@ +# +# Silan device configuration +# + +config NET_VENDOR_SILAN + bool "Silan devices" + default y + depends on PCI && EXPERIMENTAL + ---help--- + If you have a network (Ethernet) card belonging to this class, say Y + and read the Ethernet-HOWTO, available from + . + + Note that the answer to this question doesn't directly affect the + kernel: saying N will just cause the configurator to skip all + the questions about Silan devices. If you say Y, you will be asked for + your specific card in the following questions. + +if NET_VENDOR_SILAN + +config SC92031 + tristate "Silan SC92031 PCI Fast Ethernet Adapter driver (EXPERIMENTAL)" + depends on PCI && EXPERIMENTAL + select CRC32 + ---help--- + This is a driver for the Fast Ethernet PCI network cards based on + the Silan SC92031 chip (sometimes also called Rsltek 8139D). If you + have one of these, say Y here. + + To compile this driver as a module, choose M here: the module + will be called sc92031. This is recommended. + +endif # NET_VENDOR_SILAN diff --git a/drivers/net/ethernet/silan/Makefile b/drivers/net/ethernet/silan/Makefile new file mode 100644 index 0000000..4ad3523 --- /dev/null +++ b/drivers/net/ethernet/silan/Makefile @@ -0,0 +1,5 @@ +# +# Makefile for the Silan network device drivers. +# + +obj-$(CONFIG_SC92031) += sc92031.o diff --git a/drivers/net/ethernet/silan/sc92031.c b/drivers/net/ethernet/silan/sc92031.c new file mode 100644 index 0000000..a284d64 --- /dev/null +++ b/drivers/net/ethernet/silan/sc92031.c @@ -0,0 +1,1609 @@ +/* Silan SC92031 PCI Fast Ethernet Adapter driver + * + * Based on vendor drivers: + * Silan Fast Ethernet Netcard Driver: + * MODULE_AUTHOR ("gaoyonghong"); + * MODULE_DESCRIPTION ("SILAN Fast Ethernet driver"); + * MODULE_LICENSE("GPL"); + * 8139D Fast Ethernet driver: + * (C) 2002 by gaoyonghong + * MODULE_AUTHOR ("gaoyonghong"); + * MODULE_DESCRIPTION ("Rsltek 8139D PCI Fast Ethernet Adapter driver"); + * MODULE_LICENSE("GPL"); + * Both are almost identical and seem to be based on pci-skeleton.c + * + * Rewritten for 2.6 by Cesar Eduardo Barros + * + * A datasheet for this chip can be found at + * http://www.silan.com.cn/english/product/pdf/SC92031AY.pdf + */ + +/* Note about set_mac_address: I don't know how to change the hardware + * matching, so you need to enable IFF_PROMISC when using it. + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define SC92031_NAME "sc92031" + +/* BAR 0 is MMIO, BAR 1 is PIO */ +#ifndef SC92031_USE_BAR +#define SC92031_USE_BAR 0 +#endif + +/* Maximum number of multicast addresses to filter (vs. Rx-all-multicast). */ +static int multicast_filter_limit = 64; +module_param(multicast_filter_limit, int, 0); +MODULE_PARM_DESC(multicast_filter_limit, + "Maximum number of filtered multicast addresses"); + +static int media; +module_param(media, int, 0); +MODULE_PARM_DESC(media, "Media type (0x00 = autodetect," + " 0x01 = 10M half, 0x02 = 10M full," + " 0x04 = 100M half, 0x08 = 100M full)"); + +/* Size of the in-memory receive ring. */ +#define RX_BUF_LEN_IDX 3 /* 0==8K, 1==16K, 2==32K, 3==64K ,4==128K*/ +#define RX_BUF_LEN (8192 << RX_BUF_LEN_IDX) + +/* Number of Tx descriptor registers. */ +#define NUM_TX_DESC 4 + +/* max supported ethernet frame size -- must be at least (dev->mtu+14+4).*/ +#define MAX_ETH_FRAME_SIZE 1536 + +/* Size of the Tx bounce buffers -- must be at least (dev->mtu+14+4). */ +#define TX_BUF_SIZE MAX_ETH_FRAME_SIZE +#define TX_BUF_TOT_LEN (TX_BUF_SIZE * NUM_TX_DESC) + +/* The following settings are log_2(bytes)-4: 0 == 16 bytes .. 6==1024, 7==end of packet. */ +#define RX_FIFO_THRESH 7 /* Rx buffer level before first PCI xfer. */ + +/* Time in jiffies before concluding the transmitter is hung. */ +#define TX_TIMEOUT (4*HZ) + +#define SILAN_STATS_NUM 2 /* number of ETHTOOL_GSTATS */ + +/* media options */ +#define AUTOSELECT 0x00 +#define M10_HALF 0x01 +#define M10_FULL 0x02 +#define M100_HALF 0x04 +#define M100_FULL 0x08 + + /* Symbolic offsets to registers. */ +enum silan_registers { + Config0 = 0x00, // Config0 + Config1 = 0x04, // Config1 + RxBufWPtr = 0x08, // Rx buffer writer poiter + IntrStatus = 0x0C, // Interrupt status + IntrMask = 0x10, // Interrupt mask + RxbufAddr = 0x14, // Rx buffer start address + RxBufRPtr = 0x18, // Rx buffer read pointer + Txstatusall = 0x1C, // Transmit status of all descriptors + TxStatus0 = 0x20, // Transmit status (Four 32bit registers). + TxAddr0 = 0x30, // Tx descriptors (also four 32bit). + RxConfig = 0x40, // Rx configuration + MAC0 = 0x44, // Ethernet hardware address. + MAR0 = 0x4C, // Multicast filter. + RxStatus0 = 0x54, // Rx status + TxConfig = 0x5C, // Tx configuration + PhyCtrl = 0x60, // physical control + FlowCtrlConfig = 0x64, // flow control + Miicmd0 = 0x68, // Mii command0 register + Miicmd1 = 0x6C, // Mii command1 register + Miistatus = 0x70, // Mii status register + Timercnt = 0x74, // Timer counter register + TimerIntr = 0x78, // Timer interrupt register + PMConfig = 0x7C, // Power Manager configuration + CRC0 = 0x80, // Power Manager CRC ( Two 32bit regisers) + Wakeup0 = 0x88, // power Manager wakeup( Eight 64bit regiser) + LSBCRC0 = 0xC8, // power Manager LSBCRC(Two 32bit regiser) + TestD0 = 0xD0, + TestD4 = 0xD4, + TestD8 = 0xD8, +}; + +#define MII_JAB 16 +#define MII_OutputStatus 24 + +#define PHY_16_JAB_ENB 0x1000 +#define PHY_16_PORT_ENB 0x1 + +enum IntrStatusBits { + LinkFail = 0x80000000, + LinkOK = 0x40000000, + TimeOut = 0x20000000, + RxOverflow = 0x0040, + RxOK = 0x0020, + TxOK = 0x0001, + IntrBits = LinkFail|LinkOK|TimeOut|RxOverflow|RxOK|TxOK, +}; + +enum TxStatusBits { + TxCarrierLost = 0x20000000, + TxAborted = 0x10000000, + TxOutOfWindow = 0x08000000, + TxNccShift = 22, + EarlyTxThresShift = 16, + TxStatOK = 0x8000, + TxUnderrun = 0x4000, + TxOwn = 0x2000, +}; + +enum RxStatusBits { + RxStatesOK = 0x80000, + RxBadAlign = 0x40000, + RxHugeFrame = 0x20000, + RxSmallFrame = 0x10000, + RxCRCOK = 0x8000, + RxCrlFrame = 0x4000, + Rx_Broadcast = 0x2000, + Rx_Multicast = 0x1000, + RxAddrMatch = 0x0800, + MiiErr = 0x0400, +}; + +enum RxConfigBits { + RxFullDx = 0x80000000, + RxEnb = 0x40000000, + RxSmall = 0x20000000, + RxHuge = 0x10000000, + RxErr = 0x08000000, + RxAllphys = 0x04000000, + RxMulticast = 0x02000000, + RxBroadcast = 0x01000000, + RxLoopBack = (1 << 23) | (1 << 22), + LowThresholdShift = 12, + HighThresholdShift = 2, +}; + +enum TxConfigBits { + TxFullDx = 0x80000000, + TxEnb = 0x40000000, + TxEnbPad = 0x20000000, + TxEnbHuge = 0x10000000, + TxEnbFCS = 0x08000000, + TxNoBackOff = 0x04000000, + TxEnbPrem = 0x02000000, + TxCareLostCrs = 0x1000000, + TxExdCollNum = 0xf00000, + TxDataRate = 0x80000, +}; + +enum PhyCtrlconfigbits { + PhyCtrlAne = 0x80000000, + PhyCtrlSpd100 = 0x40000000, + PhyCtrlSpd10 = 0x20000000, + PhyCtrlPhyBaseAddr = 0x1f000000, + PhyCtrlDux = 0x800000, + PhyCtrlReset = 0x400000, +}; + +enum FlowCtrlConfigBits { + FlowCtrlFullDX = 0x80000000, + FlowCtrlEnb = 0x40000000, +}; + +enum Config0Bits { + Cfg0_Reset = 0x80000000, + Cfg0_Anaoff = 0x40000000, + Cfg0_LDPS = 0x20000000, +}; + +enum Config1Bits { + Cfg1_EarlyRx = 1 << 31, + Cfg1_EarlyTx = 1 << 30, + + //rx buffer size + Cfg1_Rcv8K = 0x0, + Cfg1_Rcv16K = 0x1, + Cfg1_Rcv32K = 0x3, + Cfg1_Rcv64K = 0x7, + Cfg1_Rcv128K = 0xf, +}; + +enum MiiCmd0Bits { + Mii_Divider = 0x20000000, + Mii_WRITE = 0x400000, + Mii_READ = 0x200000, + Mii_SCAN = 0x100000, + Mii_Tamod = 0x80000, + Mii_Drvmod = 0x40000, + Mii_mdc = 0x20000, + Mii_mdoen = 0x10000, + Mii_mdo = 0x8000, + Mii_mdi = 0x4000, +}; + +enum MiiStatusBits { + Mii_StatusBusy = 0x80000000, +}; + +enum PMConfigBits { + PM_Enable = 1 << 31, + PM_LongWF = 1 << 30, + PM_Magic = 1 << 29, + PM_LANWake = 1 << 28, + PM_LWPTN = (1 << 27 | 1<< 26), + PM_LinkUp = 1 << 25, + PM_WakeUp = 1 << 24, +}; + +/* Locking rules: + * priv->lock protects most of the fields of priv and most of the + * hardware registers. It does not have to protect against softirqs + * between sc92031_disable_interrupts and sc92031_enable_interrupts; + * it also does not need to be used in ->open and ->stop while the + * device interrupts are off. + * Not having to protect against softirqs is very useful due to heavy + * use of mdelay() at _sc92031_reset. + * Functions prefixed with _sc92031_ must be called with the lock held; + * functions prefixed with sc92031_ must be called without the lock held. + * Use mmiowb() before unlocking if the hardware was written to. + */ + +/* Locking rules for the interrupt: + * - the interrupt and the tasklet never run at the same time + * - neither run between sc92031_disable_interrupts and + * sc92031_enable_interrupt + */ + +struct sc92031_priv { + spinlock_t lock; + /* iomap.h cookie */ + void __iomem *port_base; + /* pci device structure */ + struct pci_dev *pdev; + /* tasklet */ + struct tasklet_struct tasklet; + + /* CPU address of rx ring */ + void *rx_ring; + /* PCI address of rx ring */ + dma_addr_t rx_ring_dma_addr; + /* PCI address of rx ring read pointer */ + dma_addr_t rx_ring_tail; + + /* tx ring write index */ + unsigned tx_head; + /* tx ring read index */ + unsigned tx_tail; + /* CPU address of tx bounce buffer */ + void *tx_bufs; + /* PCI address of tx bounce buffer */ + dma_addr_t tx_bufs_dma_addr; + + /* copies of some hardware registers */ + u32 intr_status; + atomic_t intr_mask; + u32 rx_config; + u32 tx_config; + u32 pm_config; + + /* copy of some flags from dev->flags */ + unsigned int mc_flags; + + /* for ETHTOOL_GSTATS */ + u64 tx_timeouts; + u64 rx_loss; + + /* for dev->get_stats */ + long rx_value; +}; + +/* I don't know which registers can be safely read; however, I can guess + * MAC0 is one of them. */ +static inline void _sc92031_dummy_read(void __iomem *port_base) +{ + ioread32(port_base + MAC0); +} + +static u32 _sc92031_mii_wait(void __iomem *port_base) +{ + u32 mii_status; + + do { + udelay(10); + mii_status = ioread32(port_base + Miistatus); + } while (mii_status & Mii_StatusBusy); + + return mii_status; +} + +static u32 _sc92031_mii_cmd(void __iomem *port_base, u32 cmd0, u32 cmd1) +{ + iowrite32(Mii_Divider, port_base + Miicmd0); + + _sc92031_mii_wait(port_base); + + iowrite32(cmd1, port_base + Miicmd1); + iowrite32(Mii_Divider | cmd0, port_base + Miicmd0); + + return _sc92031_mii_wait(port_base); +} + +static void _sc92031_mii_scan(void __iomem *port_base) +{ + _sc92031_mii_cmd(port_base, Mii_SCAN, 0x1 << 6); +} + +static u16 _sc92031_mii_read(void __iomem *port_base, unsigned reg) +{ + return _sc92031_mii_cmd(port_base, Mii_READ, reg << 6) >> 13; +} + +static void _sc92031_mii_write(void __iomem *port_base, unsigned reg, u16 val) +{ + _sc92031_mii_cmd(port_base, Mii_WRITE, (reg << 6) | ((u32)val << 11)); +} + +static void sc92031_disable_interrupts(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + /* tell the tasklet/interrupt not to enable interrupts */ + atomic_set(&priv->intr_mask, 0); + wmb(); + + /* stop interrupts */ + iowrite32(0, port_base + IntrMask); + _sc92031_dummy_read(port_base); + mmiowb(); + + /* wait for any concurrent interrupt/tasklet to finish */ + synchronize_irq(dev->irq); + tasklet_disable(&priv->tasklet); +} + +static void sc92031_enable_interrupts(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + tasklet_enable(&priv->tasklet); + + atomic_set(&priv->intr_mask, IntrBits); + wmb(); + + iowrite32(IntrBits, port_base + IntrMask); + mmiowb(); +} + +static void _sc92031_disable_tx_rx(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + priv->rx_config &= ~RxEnb; + priv->tx_config &= ~TxEnb; + iowrite32(priv->rx_config, port_base + RxConfig); + iowrite32(priv->tx_config, port_base + TxConfig); +} + +static void _sc92031_enable_tx_rx(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + priv->rx_config |= RxEnb; + priv->tx_config |= TxEnb; + iowrite32(priv->rx_config, port_base + RxConfig); + iowrite32(priv->tx_config, port_base + TxConfig); +} + +static void _sc92031_tx_clear(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + while (priv->tx_head - priv->tx_tail > 0) { + priv->tx_tail++; + dev->stats.tx_dropped++; + } + priv->tx_head = priv->tx_tail = 0; +} + +static void _sc92031_set_mar(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 mar0 = 0, mar1 = 0; + + if ((dev->flags & IFF_PROMISC) || + netdev_mc_count(dev) > multicast_filter_limit || + (dev->flags & IFF_ALLMULTI)) + mar0 = mar1 = 0xffffffff; + else if (dev->flags & IFF_MULTICAST) { + struct netdev_hw_addr *ha; + + netdev_for_each_mc_addr(ha, dev) { + u32 crc; + unsigned bit = 0; + + crc = ~ether_crc(ETH_ALEN, ha->addr); + crc >>= 24; + + if (crc & 0x01) bit |= 0x02; + if (crc & 0x02) bit |= 0x01; + if (crc & 0x10) bit |= 0x20; + if (crc & 0x20) bit |= 0x10; + if (crc & 0x40) bit |= 0x08; + if (crc & 0x80) bit |= 0x04; + + if (bit > 31) + mar0 |= 0x1 << (bit - 32); + else + mar1 |= 0x1 << bit; + } + } + + iowrite32(mar0, port_base + MAR0); + iowrite32(mar1, port_base + MAR0 + 4); +} + +static void _sc92031_set_rx_config(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + unsigned int old_mc_flags; + u32 rx_config_bits = 0; + + old_mc_flags = priv->mc_flags; + + if (dev->flags & IFF_PROMISC) + rx_config_bits |= RxSmall | RxHuge | RxErr | RxBroadcast + | RxMulticast | RxAllphys; + + if (dev->flags & (IFF_ALLMULTI | IFF_MULTICAST)) + rx_config_bits |= RxMulticast; + + if (dev->flags & IFF_BROADCAST) + rx_config_bits |= RxBroadcast; + + priv->rx_config &= ~(RxSmall | RxHuge | RxErr | RxBroadcast + | RxMulticast | RxAllphys); + priv->rx_config |= rx_config_bits; + + priv->mc_flags = dev->flags & (IFF_PROMISC | IFF_ALLMULTI + | IFF_MULTICAST | IFF_BROADCAST); + + if (netif_carrier_ok(dev) && priv->mc_flags != old_mc_flags) + iowrite32(priv->rx_config, port_base + RxConfig); +} + +static bool _sc92031_check_media(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u16 bmsr; + + bmsr = _sc92031_mii_read(port_base, MII_BMSR); + rmb(); + if (bmsr & BMSR_LSTATUS) { + bool speed_100, duplex_full; + u32 flow_ctrl_config = 0; + u16 output_status = _sc92031_mii_read(port_base, + MII_OutputStatus); + _sc92031_mii_scan(port_base); + + speed_100 = output_status & 0x2; + duplex_full = output_status & 0x4; + + /* Initial Tx/Rx configuration */ + priv->rx_config = (0x40 << LowThresholdShift) | (0x1c0 << HighThresholdShift); + priv->tx_config = 0x48800000; + + /* NOTE: vendor driver had dead code here to enable tx padding */ + + if (!speed_100) + priv->tx_config |= 0x80000; + + // configure rx mode + _sc92031_set_rx_config(dev); + + if (duplex_full) { + priv->rx_config |= RxFullDx; + priv->tx_config |= TxFullDx; + flow_ctrl_config = FlowCtrlFullDX | FlowCtrlEnb; + } else { + priv->rx_config &= ~RxFullDx; + priv->tx_config &= ~TxFullDx; + } + + _sc92031_set_mar(dev); + _sc92031_set_rx_config(dev); + _sc92031_enable_tx_rx(dev); + iowrite32(flow_ctrl_config, port_base + FlowCtrlConfig); + + netif_carrier_on(dev); + + if (printk_ratelimit()) + printk(KERN_INFO "%s: link up, %sMbps, %s-duplex\n", + dev->name, + speed_100 ? "100" : "10", + duplex_full ? "full" : "half"); + return true; + } else { + _sc92031_mii_scan(port_base); + + netif_carrier_off(dev); + + _sc92031_disable_tx_rx(dev); + + if (printk_ratelimit()) + printk(KERN_INFO "%s: link down\n", dev->name); + return false; + } +} + +static void _sc92031_phy_reset(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 phy_ctrl; + + phy_ctrl = ioread32(port_base + PhyCtrl); + phy_ctrl &= ~(PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10); + phy_ctrl |= PhyCtrlAne | PhyCtrlReset; + + switch (media) { + default: + case AUTOSELECT: + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10; + break; + case M10_HALF: + phy_ctrl |= PhyCtrlSpd10; + break; + case M10_FULL: + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd10; + break; + case M100_HALF: + phy_ctrl |= PhyCtrlSpd100; + break; + case M100_FULL: + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100; + break; + } + + iowrite32(phy_ctrl, port_base + PhyCtrl); + mdelay(10); + + phy_ctrl &= ~PhyCtrlReset; + iowrite32(phy_ctrl, port_base + PhyCtrl); + mdelay(1); + + _sc92031_mii_write(port_base, MII_JAB, + PHY_16_JAB_ENB | PHY_16_PORT_ENB); + _sc92031_mii_scan(port_base); + + netif_carrier_off(dev); + netif_stop_queue(dev); +} + +static void _sc92031_reset(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + /* disable PM */ + iowrite32(0, port_base + PMConfig); + + /* soft reset the chip */ + iowrite32(Cfg0_Reset, port_base + Config0); + mdelay(200); + + iowrite32(0, port_base + Config0); + mdelay(10); + + /* disable interrupts */ + iowrite32(0, port_base + IntrMask); + + /* clear multicast address */ + iowrite32(0, port_base + MAR0); + iowrite32(0, port_base + MAR0 + 4); + + /* init rx ring */ + iowrite32(priv->rx_ring_dma_addr, port_base + RxbufAddr); + priv->rx_ring_tail = priv->rx_ring_dma_addr; + + /* init tx ring */ + _sc92031_tx_clear(dev); + + /* clear old register values */ + priv->intr_status = 0; + atomic_set(&priv->intr_mask, 0); + priv->rx_config = 0; + priv->tx_config = 0; + priv->mc_flags = 0; + + /* configure rx buffer size */ + /* NOTE: vendor driver had dead code here to enable early tx/rx */ + iowrite32(Cfg1_Rcv64K, port_base + Config1); + + _sc92031_phy_reset(dev); + _sc92031_check_media(dev); + + /* calculate rx fifo overflow */ + priv->rx_value = 0; + + /* enable PM */ + iowrite32(priv->pm_config, port_base + PMConfig); + + /* clear intr register */ + ioread32(port_base + IntrStatus); +} + +static void _sc92031_tx_tasklet(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + unsigned old_tx_tail; + unsigned entry; + u32 tx_status; + + old_tx_tail = priv->tx_tail; + while (priv->tx_head - priv->tx_tail > 0) { + entry = priv->tx_tail % NUM_TX_DESC; + tx_status = ioread32(port_base + TxStatus0 + entry * 4); + + if (!(tx_status & (TxStatOK | TxUnderrun | TxAborted))) + break; + + priv->tx_tail++; + + if (tx_status & TxStatOK) { + dev->stats.tx_bytes += tx_status & 0x1fff; + dev->stats.tx_packets++; + /* Note: TxCarrierLost is always asserted at 100mbps. */ + dev->stats.collisions += (tx_status >> 22) & 0xf; + } + + if (tx_status & (TxOutOfWindow | TxAborted)) { + dev->stats.tx_errors++; + + if (tx_status & TxAborted) + dev->stats.tx_aborted_errors++; + + if (tx_status & TxCarrierLost) + dev->stats.tx_carrier_errors++; + + if (tx_status & TxOutOfWindow) + dev->stats.tx_window_errors++; + } + + if (tx_status & TxUnderrun) + dev->stats.tx_fifo_errors++; + } + + if (priv->tx_tail != old_tx_tail) + if (netif_queue_stopped(dev)) + netif_wake_queue(dev); +} + +static void _sc92031_rx_tasklet_error(struct net_device *dev, + u32 rx_status, unsigned rx_size) +{ + if(rx_size > (MAX_ETH_FRAME_SIZE + 4) || rx_size < 16) { + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; + } + + if (!(rx_status & RxStatesOK)) { + dev->stats.rx_errors++; + + if (rx_status & (RxHugeFrame | RxSmallFrame)) + dev->stats.rx_length_errors++; + + if (rx_status & RxBadAlign) + dev->stats.rx_frame_errors++; + + if (!(rx_status & RxCRCOK)) + dev->stats.rx_crc_errors++; + } else { + struct sc92031_priv *priv = netdev_priv(dev); + priv->rx_loss++; + } +} + +static void _sc92031_rx_tasklet(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + dma_addr_t rx_ring_head; + unsigned rx_len; + unsigned rx_ring_offset; + void *rx_ring = priv->rx_ring; + + rx_ring_head = ioread32(port_base + RxBufWPtr); + rmb(); + + /* rx_ring_head is only 17 bits in the RxBufWPtr register. + * we need to change it to 32 bits physical address + */ + rx_ring_head &= (dma_addr_t)(RX_BUF_LEN - 1); + rx_ring_head |= priv->rx_ring_dma_addr & ~(dma_addr_t)(RX_BUF_LEN - 1); + if (rx_ring_head < priv->rx_ring_dma_addr) + rx_ring_head += RX_BUF_LEN; + + if (rx_ring_head >= priv->rx_ring_tail) + rx_len = rx_ring_head - priv->rx_ring_tail; + else + rx_len = RX_BUF_LEN - (priv->rx_ring_tail - rx_ring_head); + + if (!rx_len) + return; + + if (unlikely(rx_len > RX_BUF_LEN)) { + if (printk_ratelimit()) + printk(KERN_ERR "%s: rx packets length > rx buffer\n", + dev->name); + return; + } + + rx_ring_offset = (priv->rx_ring_tail - priv->rx_ring_dma_addr) % RX_BUF_LEN; + + while (rx_len) { + u32 rx_status; + unsigned rx_size, rx_size_align, pkt_size; + struct sk_buff *skb; + + rx_status = le32_to_cpup((__le32 *)(rx_ring + rx_ring_offset)); + rmb(); + + rx_size = rx_status >> 20; + rx_size_align = (rx_size + 3) & ~3; // for 4 bytes aligned + pkt_size = rx_size - 4; // Omit the four octet CRC from the length. + + rx_ring_offset = (rx_ring_offset + 4) % RX_BUF_LEN; + + if (unlikely(rx_status == 0 || + rx_size > (MAX_ETH_FRAME_SIZE + 4) || + rx_size < 16 || + !(rx_status & RxStatesOK))) { + _sc92031_rx_tasklet_error(dev, rx_status, rx_size); + break; + } + + if (unlikely(rx_size_align + 4 > rx_len)) { + if (printk_ratelimit()) + printk(KERN_ERR "%s: rx_len is too small\n", dev->name); + break; + } + + rx_len -= rx_size_align + 4; + + skb = netdev_alloc_skb_ip_align(dev, pkt_size); + if (unlikely(!skb)) { + if (printk_ratelimit()) + printk(KERN_ERR "%s: Couldn't allocate a skb_buff for a packet of size %u\n", + dev->name, pkt_size); + goto next; + } + + if ((rx_ring_offset + pkt_size) > RX_BUF_LEN) { + memcpy(skb_put(skb, RX_BUF_LEN - rx_ring_offset), + rx_ring + rx_ring_offset, RX_BUF_LEN - rx_ring_offset); + memcpy(skb_put(skb, pkt_size - (RX_BUF_LEN - rx_ring_offset)), + rx_ring, pkt_size - (RX_BUF_LEN - rx_ring_offset)); + } else { + memcpy(skb_put(skb, pkt_size), rx_ring + rx_ring_offset, pkt_size); + } + + skb->protocol = eth_type_trans(skb, dev); + netif_rx(skb); + + dev->stats.rx_bytes += pkt_size; + dev->stats.rx_packets++; + + if (rx_status & Rx_Multicast) + dev->stats.multicast++; + + next: + rx_ring_offset = (rx_ring_offset + rx_size_align) % RX_BUF_LEN; + } + mb(); + + priv->rx_ring_tail = rx_ring_head; + iowrite32(priv->rx_ring_tail, port_base + RxBufRPtr); +} + +static void _sc92031_link_tasklet(struct net_device *dev) +{ + if (_sc92031_check_media(dev)) + netif_wake_queue(dev); + else { + netif_stop_queue(dev); + dev->stats.tx_carrier_errors++; + } +} + +static void sc92031_tasklet(unsigned long data) +{ + struct net_device *dev = (struct net_device *)data; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 intr_status, intr_mask; + + intr_status = priv->intr_status; + + spin_lock(&priv->lock); + + if (unlikely(!netif_running(dev))) + goto out; + + if (intr_status & TxOK) + _sc92031_tx_tasklet(dev); + + if (intr_status & RxOK) + _sc92031_rx_tasklet(dev); + + if (intr_status & RxOverflow) + dev->stats.rx_errors++; + + if (intr_status & TimeOut) { + dev->stats.rx_errors++; + dev->stats.rx_length_errors++; + } + + if (intr_status & (LinkFail | LinkOK)) + _sc92031_link_tasklet(dev); + +out: + intr_mask = atomic_read(&priv->intr_mask); + rmb(); + + iowrite32(intr_mask, port_base + IntrMask); + mmiowb(); + + spin_unlock(&priv->lock); +} + +static irqreturn_t sc92031_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 intr_status, intr_mask; + + /* mask interrupts before clearing IntrStatus */ + iowrite32(0, port_base + IntrMask); + _sc92031_dummy_read(port_base); + + intr_status = ioread32(port_base + IntrStatus); + if (unlikely(intr_status == 0xffffffff)) + return IRQ_NONE; // hardware has gone missing + + intr_status &= IntrBits; + if (!intr_status) + goto out_none; + + priv->intr_status = intr_status; + tasklet_schedule(&priv->tasklet); + + return IRQ_HANDLED; + +out_none: + intr_mask = atomic_read(&priv->intr_mask); + rmb(); + + iowrite32(intr_mask, port_base + IntrMask); + mmiowb(); + + return IRQ_NONE; +} + +static struct net_device_stats *sc92031_get_stats(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + + // FIXME I do not understand what is this trying to do. + if (netif_running(dev)) { + int temp; + + spin_lock_bh(&priv->lock); + + /* Update the error count. */ + temp = (ioread32(port_base + RxStatus0) >> 16) & 0xffff; + + if (temp == 0xffff) { + priv->rx_value += temp; + dev->stats.rx_fifo_errors = priv->rx_value; + } else + dev->stats.rx_fifo_errors = temp + priv->rx_value; + + spin_unlock_bh(&priv->lock); + } + + return &dev->stats; +} + +static netdev_tx_t sc92031_start_xmit(struct sk_buff *skb, + struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + unsigned len; + unsigned entry; + u32 tx_status; + + if (unlikely(skb->len > TX_BUF_SIZE)) { + dev->stats.tx_dropped++; + goto out; + } + + spin_lock(&priv->lock); + + if (unlikely(!netif_carrier_ok(dev))) { + dev->stats.tx_dropped++; + goto out_unlock; + } + + BUG_ON(priv->tx_head - priv->tx_tail >= NUM_TX_DESC); + + entry = priv->tx_head++ % NUM_TX_DESC; + + skb_copy_and_csum_dev(skb, priv->tx_bufs + entry * TX_BUF_SIZE); + + len = skb->len; + if (len < ETH_ZLEN) { + memset(priv->tx_bufs + entry * TX_BUF_SIZE + len, + 0, ETH_ZLEN - len); + len = ETH_ZLEN; + } + + wmb(); + + if (len < 100) + tx_status = len; + else if (len < 300) + tx_status = 0x30000 | len; + else + tx_status = 0x50000 | len; + + iowrite32(priv->tx_bufs_dma_addr + entry * TX_BUF_SIZE, + port_base + TxAddr0 + entry * 4); + iowrite32(tx_status, port_base + TxStatus0 + entry * 4); + mmiowb(); + + if (priv->tx_head - priv->tx_tail >= NUM_TX_DESC) + netif_stop_queue(dev); + +out_unlock: + spin_unlock(&priv->lock); + +out: + dev_kfree_skb(skb); + + return NETDEV_TX_OK; +} + +static int sc92031_open(struct net_device *dev) +{ + int err; + struct sc92031_priv *priv = netdev_priv(dev); + struct pci_dev *pdev = priv->pdev; + + priv->rx_ring = pci_alloc_consistent(pdev, RX_BUF_LEN, + &priv->rx_ring_dma_addr); + if (unlikely(!priv->rx_ring)) { + err = -ENOMEM; + goto out_alloc_rx_ring; + } + + priv->tx_bufs = pci_alloc_consistent(pdev, TX_BUF_TOT_LEN, + &priv->tx_bufs_dma_addr); + if (unlikely(!priv->tx_bufs)) { + err = -ENOMEM; + goto out_alloc_tx_bufs; + } + priv->tx_head = priv->tx_tail = 0; + + err = request_irq(pdev->irq, sc92031_interrupt, + IRQF_SHARED, dev->name, dev); + if (unlikely(err < 0)) + goto out_request_irq; + + priv->pm_config = 0; + + /* Interrupts already disabled by sc92031_stop or sc92031_probe */ + spin_lock_bh(&priv->lock); + + _sc92031_reset(dev); + mmiowb(); + + spin_unlock_bh(&priv->lock); + sc92031_enable_interrupts(dev); + + if (netif_carrier_ok(dev)) + netif_start_queue(dev); + else + netif_tx_disable(dev); + + return 0; + +out_request_irq: + pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs, + priv->tx_bufs_dma_addr); +out_alloc_tx_bufs: + pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring, + priv->rx_ring_dma_addr); +out_alloc_rx_ring: + return err; +} + +static int sc92031_stop(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + struct pci_dev *pdev = priv->pdev; + + netif_tx_disable(dev); + + /* Disable interrupts, stop Tx and Rx. */ + sc92031_disable_interrupts(dev); + + spin_lock_bh(&priv->lock); + + _sc92031_disable_tx_rx(dev); + _sc92031_tx_clear(dev); + mmiowb(); + + spin_unlock_bh(&priv->lock); + + free_irq(pdev->irq, dev); + pci_free_consistent(pdev, TX_BUF_TOT_LEN, priv->tx_bufs, + priv->tx_bufs_dma_addr); + pci_free_consistent(pdev, RX_BUF_LEN, priv->rx_ring, + priv->rx_ring_dma_addr); + + return 0; +} + +static void sc92031_set_multicast_list(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + spin_lock_bh(&priv->lock); + + _sc92031_set_mar(dev); + _sc92031_set_rx_config(dev); + mmiowb(); + + spin_unlock_bh(&priv->lock); +} + +static void sc92031_tx_timeout(struct net_device *dev) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + /* Disable interrupts by clearing the interrupt mask.*/ + sc92031_disable_interrupts(dev); + + spin_lock(&priv->lock); + + priv->tx_timeouts++; + + _sc92031_reset(dev); + mmiowb(); + + spin_unlock(&priv->lock); + + /* enable interrupts */ + sc92031_enable_interrupts(dev); + + if (netif_carrier_ok(dev)) + netif_wake_queue(dev); +} + +#ifdef CONFIG_NET_POLL_CONTROLLER +static void sc92031_poll_controller(struct net_device *dev) +{ + disable_irq(dev->irq); + if (sc92031_interrupt(dev->irq, dev) != IRQ_NONE) + sc92031_tasklet((unsigned long)dev); + enable_irq(dev->irq); +} +#endif + +static int sc92031_ethtool_get_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u8 phy_address; + u32 phy_ctrl; + u16 output_status; + + spin_lock_bh(&priv->lock); + + phy_address = ioread32(port_base + Miicmd1) >> 27; + phy_ctrl = ioread32(port_base + PhyCtrl); + + output_status = _sc92031_mii_read(port_base, MII_OutputStatus); + _sc92031_mii_scan(port_base); + mmiowb(); + + spin_unlock_bh(&priv->lock); + + cmd->supported = SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full + | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full + | SUPPORTED_Autoneg | SUPPORTED_TP | SUPPORTED_MII; + + cmd->advertising = ADVERTISED_TP | ADVERTISED_MII; + + if ((phy_ctrl & (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10)) + == (PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10)) + cmd->advertising |= ADVERTISED_Autoneg; + + if ((phy_ctrl & PhyCtrlSpd10) == PhyCtrlSpd10) + cmd->advertising |= ADVERTISED_10baseT_Half; + + if ((phy_ctrl & (PhyCtrlSpd10 | PhyCtrlDux)) + == (PhyCtrlSpd10 | PhyCtrlDux)) + cmd->advertising |= ADVERTISED_10baseT_Full; + + if ((phy_ctrl & PhyCtrlSpd100) == PhyCtrlSpd100) + cmd->advertising |= ADVERTISED_100baseT_Half; + + if ((phy_ctrl & (PhyCtrlSpd100 | PhyCtrlDux)) + == (PhyCtrlSpd100 | PhyCtrlDux)) + cmd->advertising |= ADVERTISED_100baseT_Full; + + if (phy_ctrl & PhyCtrlAne) + cmd->advertising |= ADVERTISED_Autoneg; + + ethtool_cmd_speed_set(cmd, + (output_status & 0x2) ? SPEED_100 : SPEED_10); + cmd->duplex = (output_status & 0x4) ? DUPLEX_FULL : DUPLEX_HALF; + cmd->port = PORT_MII; + cmd->phy_address = phy_address; + cmd->transceiver = XCVR_INTERNAL; + cmd->autoneg = (phy_ctrl & PhyCtrlAne) ? AUTONEG_ENABLE : AUTONEG_DISABLE; + + return 0; +} + +static int sc92031_ethtool_set_settings(struct net_device *dev, + struct ethtool_cmd *cmd) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 speed = ethtool_cmd_speed(cmd); + u32 phy_ctrl; + u32 old_phy_ctrl; + + if (!(speed == SPEED_10 || speed == SPEED_100)) + return -EINVAL; + if (!(cmd->duplex == DUPLEX_HALF || cmd->duplex == DUPLEX_FULL)) + return -EINVAL; + if (!(cmd->port == PORT_MII)) + return -EINVAL; + if (!(cmd->phy_address == 0x1f)) + return -EINVAL; + if (!(cmd->transceiver == XCVR_INTERNAL)) + return -EINVAL; + if (!(cmd->autoneg == AUTONEG_DISABLE || cmd->autoneg == AUTONEG_ENABLE)) + return -EINVAL; + + if (cmd->autoneg == AUTONEG_ENABLE) { + if (!(cmd->advertising & (ADVERTISED_Autoneg + | ADVERTISED_100baseT_Full + | ADVERTISED_100baseT_Half + | ADVERTISED_10baseT_Full + | ADVERTISED_10baseT_Half))) + return -EINVAL; + + phy_ctrl = PhyCtrlAne; + + // FIXME: I'm not sure what the original code was trying to do + if (cmd->advertising & ADVERTISED_Autoneg) + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100 | PhyCtrlSpd10; + if (cmd->advertising & ADVERTISED_100baseT_Full) + phy_ctrl |= PhyCtrlDux | PhyCtrlSpd100; + if (cmd->advertising & ADVERTISED_100baseT_Half) + phy_ctrl |= PhyCtrlSpd100; + if (cmd->advertising & ADVERTISED_10baseT_Full) + phy_ctrl |= PhyCtrlSpd10 | PhyCtrlDux; + if (cmd->advertising & ADVERTISED_10baseT_Half) + phy_ctrl |= PhyCtrlSpd10; + } else { + // FIXME: Whole branch guessed + phy_ctrl = 0; + + if (speed == SPEED_10) + phy_ctrl |= PhyCtrlSpd10; + else /* cmd->speed == SPEED_100 */ + phy_ctrl |= PhyCtrlSpd100; + + if (cmd->duplex == DUPLEX_FULL) + phy_ctrl |= PhyCtrlDux; + } + + spin_lock_bh(&priv->lock); + + old_phy_ctrl = ioread32(port_base + PhyCtrl); + phy_ctrl |= old_phy_ctrl & ~(PhyCtrlAne | PhyCtrlDux + | PhyCtrlSpd100 | PhyCtrlSpd10); + if (phy_ctrl != old_phy_ctrl) + iowrite32(phy_ctrl, port_base + PhyCtrl); + + spin_unlock_bh(&priv->lock); + + return 0; +} + +static void sc92031_ethtool_get_wol(struct net_device *dev, + struct ethtool_wolinfo *wolinfo) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 pm_config; + + spin_lock_bh(&priv->lock); + pm_config = ioread32(port_base + PMConfig); + spin_unlock_bh(&priv->lock); + + // FIXME: Guessed + wolinfo->supported = WAKE_PHY | WAKE_MAGIC + | WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; + wolinfo->wolopts = 0; + + if (pm_config & PM_LinkUp) + wolinfo->wolopts |= WAKE_PHY; + + if (pm_config & PM_Magic) + wolinfo->wolopts |= WAKE_MAGIC; + + if (pm_config & PM_WakeUp) + // FIXME: Guessed + wolinfo->wolopts |= WAKE_UCAST | WAKE_MCAST | WAKE_BCAST; +} + +static int sc92031_ethtool_set_wol(struct net_device *dev, + struct ethtool_wolinfo *wolinfo) +{ + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u32 pm_config; + + spin_lock_bh(&priv->lock); + + pm_config = ioread32(port_base + PMConfig) + & ~(PM_LinkUp | PM_Magic | PM_WakeUp); + + if (wolinfo->wolopts & WAKE_PHY) + pm_config |= PM_LinkUp; + + if (wolinfo->wolopts & WAKE_MAGIC) + pm_config |= PM_Magic; + + // FIXME: Guessed + if (wolinfo->wolopts & (WAKE_UCAST | WAKE_MCAST | WAKE_BCAST)) + pm_config |= PM_WakeUp; + + priv->pm_config = pm_config; + iowrite32(pm_config, port_base + PMConfig); + mmiowb(); + + spin_unlock_bh(&priv->lock); + + return 0; +} + +static int sc92031_ethtool_nway_reset(struct net_device *dev) +{ + int err = 0; + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem *port_base = priv->port_base; + u16 bmcr; + + spin_lock_bh(&priv->lock); + + bmcr = _sc92031_mii_read(port_base, MII_BMCR); + if (!(bmcr & BMCR_ANENABLE)) { + err = -EINVAL; + goto out; + } + + _sc92031_mii_write(port_base, MII_BMCR, bmcr | BMCR_ANRESTART); + +out: + _sc92031_mii_scan(port_base); + mmiowb(); + + spin_unlock_bh(&priv->lock); + + return err; +} + +static const char sc92031_ethtool_stats_strings[SILAN_STATS_NUM][ETH_GSTRING_LEN] = { + "tx_timeout", + "rx_loss", +}; + +static void sc92031_ethtool_get_strings(struct net_device *dev, + u32 stringset, u8 *data) +{ + if (stringset == ETH_SS_STATS) + memcpy(data, sc92031_ethtool_stats_strings, + SILAN_STATS_NUM * ETH_GSTRING_LEN); +} + +static int sc92031_ethtool_get_sset_count(struct net_device *dev, int sset) +{ + switch (sset) { + case ETH_SS_STATS: + return SILAN_STATS_NUM; + default: + return -EOPNOTSUPP; + } +} + +static void sc92031_ethtool_get_ethtool_stats(struct net_device *dev, + struct ethtool_stats *stats, u64 *data) +{ + struct sc92031_priv *priv = netdev_priv(dev); + + spin_lock_bh(&priv->lock); + data[0] = priv->tx_timeouts; + data[1] = priv->rx_loss; + spin_unlock_bh(&priv->lock); +} + +static const struct ethtool_ops sc92031_ethtool_ops = { + .get_settings = sc92031_ethtool_get_settings, + .set_settings = sc92031_ethtool_set_settings, + .get_wol = sc92031_ethtool_get_wol, + .set_wol = sc92031_ethtool_set_wol, + .nway_reset = sc92031_ethtool_nway_reset, + .get_link = ethtool_op_get_link, + .get_strings = sc92031_ethtool_get_strings, + .get_sset_count = sc92031_ethtool_get_sset_count, + .get_ethtool_stats = sc92031_ethtool_get_ethtool_stats, +}; + + +static const struct net_device_ops sc92031_netdev_ops = { + .ndo_get_stats = sc92031_get_stats, + .ndo_start_xmit = sc92031_start_xmit, + .ndo_open = sc92031_open, + .ndo_stop = sc92031_stop, + .ndo_set_rx_mode = sc92031_set_multicast_list, + .ndo_change_mtu = eth_change_mtu, + .ndo_validate_addr = eth_validate_addr, + .ndo_set_mac_address = eth_mac_addr, + .ndo_tx_timeout = sc92031_tx_timeout, +#ifdef CONFIG_NET_POLL_CONTROLLER + .ndo_poll_controller = sc92031_poll_controller, +#endif +}; + +static int __devinit sc92031_probe(struct pci_dev *pdev, + const struct pci_device_id *id) +{ + int err; + void __iomem* port_base; + struct net_device *dev; + struct sc92031_priv *priv; + u32 mac0, mac1; + unsigned long base_addr; + + err = pci_enable_device(pdev); + if (unlikely(err < 0)) + goto out_enable_device; + + pci_set_master(pdev); + + err = pci_set_dma_mask(pdev, DMA_BIT_MASK(32)); + if (unlikely(err < 0)) + goto out_set_dma_mask; + + err = pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32)); + if (unlikely(err < 0)) + goto out_set_dma_mask; + + err = pci_request_regions(pdev, SC92031_NAME); + if (unlikely(err < 0)) + goto out_request_regions; + + port_base = pci_iomap(pdev, SC92031_USE_BAR, 0); + if (unlikely(!port_base)) { + err = -EIO; + goto out_iomap; + } + + dev = alloc_etherdev(sizeof(struct sc92031_priv)); + if (unlikely(!dev)) { + err = -ENOMEM; + goto out_alloc_etherdev; + } + + pci_set_drvdata(pdev, dev); + SET_NETDEV_DEV(dev, &pdev->dev); + +#if SC92031_USE_BAR == 0 + dev->mem_start = pci_resource_start(pdev, SC92031_USE_BAR); + dev->mem_end = pci_resource_end(pdev, SC92031_USE_BAR); +#elif SC92031_USE_BAR == 1 + dev->base_addr = pci_resource_start(pdev, SC92031_USE_BAR); +#endif + dev->irq = pdev->irq; + + /* faked with skb_copy_and_csum_dev */ + dev->features = NETIF_F_SG | NETIF_F_HIGHDMA | + NETIF_F_IP_CSUM | NETIF_F_IPV6_CSUM; + + dev->netdev_ops = &sc92031_netdev_ops; + dev->watchdog_timeo = TX_TIMEOUT; + dev->ethtool_ops = &sc92031_ethtool_ops; + + priv = netdev_priv(dev); + spin_lock_init(&priv->lock); + priv->port_base = port_base; + priv->pdev = pdev; + tasklet_init(&priv->tasklet, sc92031_tasklet, (unsigned long)dev); + /* Fudge tasklet count so the call to sc92031_enable_interrupts at + * sc92031_open will work correctly */ + tasklet_disable_nosync(&priv->tasklet); + + /* PCI PM Wakeup */ + iowrite32((~PM_LongWF & ~PM_LWPTN) | PM_Enable, port_base + PMConfig); + + mac0 = ioread32(port_base + MAC0); + mac1 = ioread32(port_base + MAC0 + 4); + dev->dev_addr[0] = dev->perm_addr[0] = mac0 >> 24; + dev->dev_addr[1] = dev->perm_addr[1] = mac0 >> 16; + dev->dev_addr[2] = dev->perm_addr[2] = mac0 >> 8; + dev->dev_addr[3] = dev->perm_addr[3] = mac0; + dev->dev_addr[4] = dev->perm_addr[4] = mac1 >> 8; + dev->dev_addr[5] = dev->perm_addr[5] = mac1; + + err = register_netdev(dev); + if (err < 0) + goto out_register_netdev; + +#if SC92031_USE_BAR == 0 + base_addr = dev->mem_start; +#elif SC92031_USE_BAR == 1 + base_addr = dev->base_addr; +#endif + printk(KERN_INFO "%s: SC92031 at 0x%lx, %pM, IRQ %d\n", dev->name, + base_addr, dev->dev_addr, dev->irq); + + return 0; + +out_register_netdev: + free_netdev(dev); +out_alloc_etherdev: + pci_iounmap(pdev, port_base); +out_iomap: + pci_release_regions(pdev); +out_request_regions: +out_set_dma_mask: + pci_disable_device(pdev); +out_enable_device: + return err; +} + +static void __devexit sc92031_remove(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct sc92031_priv *priv = netdev_priv(dev); + void __iomem* port_base = priv->port_base; + + unregister_netdev(dev); + free_netdev(dev); + pci_iounmap(pdev, port_base); + pci_release_regions(pdev); + pci_disable_device(pdev); +} + +static int sc92031_suspend(struct pci_dev *pdev, pm_message_t state) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct sc92031_priv *priv = netdev_priv(dev); + + pci_save_state(pdev); + + if (!netif_running(dev)) + goto out; + + netif_device_detach(dev); + + /* Disable interrupts, stop Tx and Rx. */ + sc92031_disable_interrupts(dev); + + spin_lock_bh(&priv->lock); + + _sc92031_disable_tx_rx(dev); + _sc92031_tx_clear(dev); + mmiowb(); + + spin_unlock_bh(&priv->lock); + +out: + pci_set_power_state(pdev, pci_choose_state(pdev, state)); + + return 0; +} + +static int sc92031_resume(struct pci_dev *pdev) +{ + struct net_device *dev = pci_get_drvdata(pdev); + struct sc92031_priv *priv = netdev_priv(dev); + + pci_restore_state(pdev); + pci_set_power_state(pdev, PCI_D0); + + if (!netif_running(dev)) + goto out; + + /* Interrupts already disabled by sc92031_suspend */ + spin_lock_bh(&priv->lock); + + _sc92031_reset(dev); + mmiowb(); + + spin_unlock_bh(&priv->lock); + sc92031_enable_interrupts(dev); + + netif_device_attach(dev); + + if (netif_carrier_ok(dev)) + netif_wake_queue(dev); + else + netif_tx_disable(dev); + +out: + return 0; +} + +static DEFINE_PCI_DEVICE_TABLE(sc92031_pci_device_id_table) = { + { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x2031) }, + { PCI_DEVICE(PCI_VENDOR_ID_SILAN, 0x8139) }, + { PCI_DEVICE(0x1088, 0x2031) }, + { 0, } +}; +MODULE_DEVICE_TABLE(pci, sc92031_pci_device_id_table); + +static struct pci_driver sc92031_pci_driver = { + .name = SC92031_NAME, + .id_table = sc92031_pci_device_id_table, + .probe = sc92031_probe, + .remove = __devexit_p(sc92031_remove), + .suspend = sc92031_suspend, + .resume = sc92031_resume, +}; + +static int __init sc92031_init(void) +{ + return pci_register_driver(&sc92031_pci_driver); +} + +static void __exit sc92031_exit(void) +{ + pci_unregister_driver(&sc92031_pci_driver); +} + +module_init(sc92031_init); +module_exit(sc92031_exit); + +MODULE_LICENSE("GPL"); +MODULE_AUTHOR("Cesar Eduardo Barros "); +MODULE_DESCRIPTION("Silan SC92031 PCI Fast Ethernet Adapter driver"); -- cgit v0.10.2 From 0a3360e1e18fc6bbe10bebe416db42de5fa02dbd Mon Sep 17 00:00:00 2001 From: Geert Uytterhoeven Date: Sat, 29 Oct 2011 08:09:01 +0000 Subject: net/ethernet: Move mac89x0.c from apple to cirrus Macintosh CS89x0 based ethernet cards use a Crystal Semiconductor (Now Cirrus Logic) CS89x0 chip, so the mac89x0 driver should be in drivers/net/ethernet/cirrus instead of drivers/net/ethernet/apple. This also fixes a build problem, as the driver needs a header file from the cirrus directory: drivers/net/ethernet/apple/mac89x0.c:107:20: error: cs89x0.h: No such file or directory Signed-off-by: Geert Uytterhoeven Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/apple/Kconfig b/drivers/net/ethernet/apple/Kconfig index a759d54..1375e2d 100644 --- a/drivers/net/ethernet/apple/Kconfig +++ b/drivers/net/ethernet/apple/Kconfig @@ -52,18 +52,6 @@ config BMAC To compile this driver as a module, choose M here: the module will be called bmac. -config MAC89x0 - tristate "Macintosh CS89x0 based ethernet cards" - depends on MAC - ---help--- - Support for CS89x0 chipset based Ethernet cards. If you have a - Nubus or LC-PDS network (Ethernet) card of this type, say Y and - read the Ethernet-HOWTO, available from - . - - To compile this driver as a module, choose M here. This module will - be called mac89x0. - config MACMACE bool "Macintosh (AV) onboard MACE ethernet" depends on MAC diff --git a/drivers/net/ethernet/apple/Makefile b/drivers/net/ethernet/apple/Makefile index 0d3a591..86eaa17 100644 --- a/drivers/net/ethernet/apple/Makefile +++ b/drivers/net/ethernet/apple/Makefile @@ -4,5 +4,4 @@ obj-$(CONFIG_MACE) += mace.o obj-$(CONFIG_BMAC) += bmac.o -obj-$(CONFIG_MAC89x0) += mac89x0.o obj-$(CONFIG_MACMACE) += macmace.o diff --git a/drivers/net/ethernet/apple/mac89x0.c b/drivers/net/ethernet/apple/mac89x0.c deleted file mode 100644 index 83781f3..0000000 --- a/drivers/net/ethernet/apple/mac89x0.c +++ /dev/null @@ -1,634 +0,0 @@ -/* mac89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */ -/* - Written 1996 by Russell Nelson, with reference to skeleton.c - written 1993-1994 by Donald Becker. - - This software may be used and distributed according to the terms - of the GNU General Public License, incorporated herein by reference. - - The author may be reached at nelson@crynwr.com, Crynwr - Software, 11 Grant St., Potsdam, NY 13676 - - Changelog: - - Mike Cruse : mcruse@cti-ltd.com - : Changes for Linux 2.0 compatibility. - : Added dev_id parameter in net_interrupt(), - : request_irq() and free_irq(). Just NULL for now. - - Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros - : in net_open() and net_close() so kerneld would know - : that the module is in use and wouldn't eject the - : driver prematurely. - - Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c - : as an example. Disabled autoprobing in init_module(), - : not a good thing to do to other devices while Linux - : is running from all accounts. - - Alan Cox : Removed 1.2 support, added 2.1 extra counters. - - David Huggins-Daines - - Split this off into mac89x0.c, and gutted it of all parts which are - not relevant to the existing CS8900 cards on the Macintosh - (i.e. basically the Daynaport CS and LC cards). To be precise: - - * Removed all the media-detection stuff, because these cards are - TP-only. - - * Lobotomized the ISA interrupt bogosity, because these cards use - a hardwired NuBus interrupt and a magic ISAIRQ value in the card. - - * Basically eliminated everything not relevant to getting the - cards minimally functioning on the Macintosh. - - I might add that these cards are badly designed even from the Mac - standpoint, in that Dayna, in their infinite wisdom, used NuBus slot - I/O space and NuBus interrupts for these cards, but neglected to - provide anything even remotely resembling a NuBus ROM. Therefore we - have to probe for them in a brain-damaged ISA-like fashion. - - Arnaldo Carvalho de Melo - 11/01/2001 - check kmalloc and release the allocated memory on failure in - mac89x0_probe and in init_module - use local_irq_{save,restore}(flags) in net_get_stat, not just - local_irq_{dis,en}able() -*/ - -static char *version = -"cs89x0.c:v1.02 11/26/96 Russell Nelson \n"; - -/* ======================= configure the driver here ======================= */ - -/* use 0 for production, 1 for verification, >2 for debug */ -#ifndef NET_DEBUG -#define NET_DEBUG 0 -#endif - -/* ======================= end of configuration ======================= */ - - -/* Always include 'config.h' first in case the user wants to turn on - or override something. */ -#include - -/* - Sources: - - Crynwr packet driver epktisa. - - Crystal Semiconductor data sheets. - -*/ - -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include -#include -#include -#include - -#include "cs89x0.h" - -static unsigned int net_debug = NET_DEBUG; - -/* Information that need to be kept for each board. */ -struct net_local { - int chip_type; /* one of: CS8900, CS8920, CS8920M */ - char chip_revision; /* revision letter of the chip ('A'...) */ - int send_cmd; /* the propercommand used to send a packet. */ - int rx_mode; - int curr_rx_cfg; - int send_underrun; /* keep track of how many underruns in a row we get */ - struct sk_buff *skb; -}; - -/* Index to functions, as function prototypes. */ - -#if 0 -extern void reset_chip(struct net_device *dev); -#endif -static int net_open(struct net_device *dev); -static int net_send_packet(struct sk_buff *skb, struct net_device *dev); -static irqreturn_t net_interrupt(int irq, void *dev_id); -static void set_multicast_list(struct net_device *dev); -static void net_rx(struct net_device *dev); -static int net_close(struct net_device *dev); -static struct net_device_stats *net_get_stats(struct net_device *dev); -static int set_mac_address(struct net_device *dev, void *addr); - - -/* Example routines you must write ;->. */ -#define tx_done(dev) 1 - -/* For reading/writing registers ISA-style */ -static inline int -readreg_io(struct net_device *dev, int portno) -{ - nubus_writew(swab16(portno), dev->base_addr + ADD_PORT); - return swab16(nubus_readw(dev->base_addr + DATA_PORT)); -} - -static inline void -writereg_io(struct net_device *dev, int portno, int value) -{ - nubus_writew(swab16(portno), dev->base_addr + ADD_PORT); - nubus_writew(swab16(value), dev->base_addr + DATA_PORT); -} - -/* These are for reading/writing registers in shared memory */ -static inline int -readreg(struct net_device *dev, int portno) -{ - return swab16(nubus_readw(dev->mem_start + portno)); -} - -static inline void -writereg(struct net_device *dev, int portno, int value) -{ - nubus_writew(swab16(value), dev->mem_start + portno); -} - -static const struct net_device_ops mac89x0_netdev_ops = { - .ndo_open = net_open, - .ndo_stop = net_close, - .ndo_start_xmit = net_send_packet, - .ndo_get_stats = net_get_stats, - .ndo_set_rx_mode = set_multicast_list, - .ndo_set_mac_address = set_mac_address, - .ndo_validate_addr = eth_validate_addr, - .ndo_change_mtu = eth_change_mtu, -}; - -/* Probe for the CS8900 card in slot E. We won't bother looking - anywhere else until we have a really good reason to do so. */ -struct net_device * __init mac89x0_probe(int unit) -{ - struct net_device *dev; - static int once_is_enough; - struct net_local *lp; - static unsigned version_printed; - int i, slot; - unsigned rev_type = 0; - unsigned long ioaddr; - unsigned short sig; - int err = -ENODEV; - - if (!MACH_IS_MAC) - return ERR_PTR(-ENODEV); - - dev = alloc_etherdev(sizeof(struct net_local)); - if (!dev) - return ERR_PTR(-ENOMEM); - - if (unit >= 0) { - sprintf(dev->name, "eth%d", unit); - netdev_boot_setup_check(dev); - } - - if (once_is_enough) - goto out; - once_is_enough = 1; - - /* We might have to parameterize this later */ - slot = 0xE; - /* Get out now if there's a real NuBus card in slot E */ - if (nubus_find_slot(slot, NULL) != NULL) - goto out; - - /* The pseudo-ISA bits always live at offset 0x300 (gee, - wonder why...) */ - ioaddr = (unsigned long) - nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE); - { - unsigned long flags; - int card_present; - - local_irq_save(flags); - card_present = (hwreg_present((void*) ioaddr+4) && - hwreg_present((void*) ioaddr + DATA_PORT)); - local_irq_restore(flags); - - if (!card_present) - goto out; - } - - nubus_writew(0, ioaddr + ADD_PORT); - sig = nubus_readw(ioaddr + DATA_PORT); - if (sig != swab16(CHIP_EISA_ID_SIG)) - goto out; - - /* Initialize the net_device structure. */ - lp = netdev_priv(dev); - - /* Fill in the 'dev' fields. */ - dev->base_addr = ioaddr; - dev->mem_start = (unsigned long) - nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE); - dev->mem_end = dev->mem_start + 0x1000; - - /* Turn on shared memory */ - writereg_io(dev, PP_BusCTL, MEMORY_ON); - - /* get the chip type */ - rev_type = readreg(dev, PRODUCT_ID_ADD); - lp->chip_type = rev_type &~ REVISON_BITS; - lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; - - /* Check the chip type and revision in order to set the correct send command - CS8920 revision C and CS8900 revision F can use the faster send. */ - lp->send_cmd = TX_AFTER_381; - if (lp->chip_type == CS8900 && lp->chip_revision >= 'F') - lp->send_cmd = TX_NOW; - if (lp->chip_type != CS8900 && lp->chip_revision >= 'C') - lp->send_cmd = TX_NOW; - - if (net_debug && version_printed++ == 0) - printk(version); - - printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#8lx", - dev->name, - lp->chip_type==CS8900?'0':'2', - lp->chip_type==CS8920M?"M":"", - lp->chip_revision, - dev->base_addr); - - /* Try to read the MAC address */ - if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { - printk("\nmac89x0: No EEPROM, giving up now.\n"); - goto out1; - } else { - for (i = 0; i < ETH_ALEN; i += 2) { - /* Big-endian (why??!) */ - unsigned short s = readreg(dev, PP_IA + i); - dev->dev_addr[i] = s >> 8; - dev->dev_addr[i+1] = s & 0xff; - } - } - - dev->irq = SLOT2IRQ(slot); - - /* print the IRQ and ethernet address. */ - - printk(" IRQ %d ADDR %pM\n", dev->irq, dev->dev_addr); - - dev->netdev_ops = &mac89x0_netdev_ops; - - err = register_netdev(dev); - if (err) - goto out1; - return NULL; -out1: - nubus_writew(0, dev->base_addr + ADD_PORT); -out: - free_netdev(dev); - return ERR_PTR(err); -} - -#if 0 -/* This is useful for something, but I don't know what yet. */ -void __init reset_chip(struct net_device *dev) -{ - int reset_start_time; - - writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); - - /* wait 30 ms */ - msleep_interruptible(30); - - /* Wait until the chip is reset */ - reset_start_time = jiffies; - while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) - ; -} -#endif - -/* Open/initialize the board. This is called (in the current kernel) - sometime after booting when the 'ifconfig' program is run. - - This routine should set everything up anew at each open, even - registers that "should" only need to be set once at boot, so that - there is non-reboot way to recover if something goes wrong. - */ -static int -net_open(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - int i; - - /* Disable the interrupt for now */ - writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ); - - /* Grab the interrupt */ - if (request_irq(dev->irq, net_interrupt, 0, "cs89x0", dev)) - return -EAGAIN; - - /* Set up the IRQ - Apparently magic */ - if (lp->chip_type == CS8900) - writereg(dev, PP_CS8900_ISAINT, 0); - else - writereg(dev, PP_CS8920_ISAINT, 0); - - /* set the Ethernet address */ - for (i=0; i < ETH_ALEN/2; i++) - writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); - - /* Turn on both receive and transmit operations */ - writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); - - /* Receive only error free packets addressed to this card */ - lp->rx_mode = 0; - writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); - - lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; - - writereg(dev, PP_RxCFG, lp->curr_rx_cfg); - - writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL | - TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); - - writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL | - TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); - - /* now that we've got our act together, enable everything */ - writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ); - netif_start_queue(dev); - return 0; -} - -static int -net_send_packet(struct sk_buff *skb, struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - unsigned long flags; - - if (net_debug > 3) - printk("%s: sent %d byte packet of type %x\n", - dev->name, skb->len, - (skb->data[ETH_ALEN+ETH_ALEN] << 8) - | skb->data[ETH_ALEN+ETH_ALEN+1]); - - /* keep the upload from being interrupted, since we - ask the chip to start transmitting before the - whole packet has been completely uploaded. */ - local_irq_save(flags); - netif_stop_queue(dev); - - /* initiate a transmit sequence */ - writereg(dev, PP_TxCMD, lp->send_cmd); - writereg(dev, PP_TxLength, skb->len); - - /* Test to see if the chip has allocated memory for the packet */ - if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { - /* Gasp! It hasn't. But that shouldn't happen since - we're waiting for TxOk, so return 1 and requeue this packet. */ - local_irq_restore(flags); - return NETDEV_TX_BUSY; - } - - /* Write the contents of the packet */ - skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame), - skb->len+1); - - local_irq_restore(flags); - dev_kfree_skb (skb); - - return NETDEV_TX_OK; -} - -/* The typical workload of the driver: - Handle the network interface interrupts. */ -static irqreturn_t net_interrupt(int irq, void *dev_id) -{ - struct net_device *dev = dev_id; - struct net_local *lp; - int ioaddr, status; - - if (dev == NULL) { - printk ("net_interrupt(): irq %d for unknown device.\n", irq); - return IRQ_NONE; - } - - ioaddr = dev->base_addr; - lp = netdev_priv(dev); - - /* we MUST read all the events out of the ISQ, otherwise we'll never - get interrupted again. As a consequence, we can't have any limit - on the number of times we loop in the interrupt handler. The - hardware guarantees that eventually we'll run out of events. Of - course, if you're on a slow machine, and packets are arriving - faster than you can read them off, you're screwed. Hasta la - vista, baby! */ - while ((status = swab16(nubus_readw(dev->base_addr + ISQ_PORT)))) { - if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status); - switch(status & ISQ_EVENT_MASK) { - case ISQ_RECEIVER_EVENT: - /* Got a packet(s). */ - net_rx(dev); - break; - case ISQ_TRANSMITTER_EVENT: - dev->stats.tx_packets++; - netif_wake_queue(dev); - if ((status & TX_OK) == 0) - dev->stats.tx_errors++; - if (status & TX_LOST_CRS) - dev->stats.tx_carrier_errors++; - if (status & TX_SQE_ERROR) - dev->stats.tx_heartbeat_errors++; - if (status & TX_LATE_COL) - dev->stats.tx_window_errors++; - if (status & TX_16_COL) - dev->stats.tx_aborted_errors++; - break; - case ISQ_BUFFER_EVENT: - if (status & READY_FOR_TX) { - /* we tried to transmit a packet earlier, - but inexplicably ran out of buffers. - That shouldn't happen since we only ever - load one packet. Shrug. Do the right - thing anyway. */ - netif_wake_queue(dev); - } - if (status & TX_UNDERRUN) { - if (net_debug > 0) printk("%s: transmit underrun\n", dev->name); - lp->send_underrun++; - if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; - else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL; - } - break; - case ISQ_RX_MISS_EVENT: - dev->stats.rx_missed_errors += (status >> 6); - break; - case ISQ_TX_COL_EVENT: - dev->stats.collisions += (status >> 6); - break; - } - } - return IRQ_HANDLED; -} - -/* We have a good packet(s), get it/them out of the buffers. */ -static void -net_rx(struct net_device *dev) -{ - struct sk_buff *skb; - int status, length; - - status = readreg(dev, PP_RxStatus); - if ((status & RX_OK) == 0) { - dev->stats.rx_errors++; - if (status & RX_RUNT) - dev->stats.rx_length_errors++; - if (status & RX_EXTRA_DATA) - dev->stats.rx_length_errors++; - if ((status & RX_CRC_ERROR) && - !(status & (RX_EXTRA_DATA|RX_RUNT))) - /* per str 172 */ - dev->stats.rx_crc_errors++; - if (status & RX_DRIBBLE) - dev->stats.rx_frame_errors++; - return; - } - - length = readreg(dev, PP_RxLength); - /* Malloc up new buffer. */ - skb = alloc_skb(length, GFP_ATOMIC); - if (skb == NULL) { - printk("%s: Memory squeeze, dropping packet.\n", dev->name); - dev->stats.rx_dropped++; - return; - } - skb_put(skb, length); - - skb_copy_to_linear_data(skb, (void *)(dev->mem_start + PP_RxFrame), - length); - - if (net_debug > 3)printk("%s: received %d byte packet of type %x\n", - dev->name, length, - (skb->data[ETH_ALEN+ETH_ALEN] << 8) - | skb->data[ETH_ALEN+ETH_ALEN+1]); - - skb->protocol=eth_type_trans(skb,dev); - netif_rx(skb); - dev->stats.rx_packets++; - dev->stats.rx_bytes += length; -} - -/* The inverse routine to net_open(). */ -static int -net_close(struct net_device *dev) -{ - - writereg(dev, PP_RxCFG, 0); - writereg(dev, PP_TxCFG, 0); - writereg(dev, PP_BufCFG, 0); - writereg(dev, PP_BusCTL, 0); - - netif_stop_queue(dev); - - free_irq(dev->irq, dev); - - /* Update the statistics here. */ - - return 0; - -} - -/* Get the current statistics. This may be called with the card open or - closed. */ -static struct net_device_stats * -net_get_stats(struct net_device *dev) -{ - unsigned long flags; - - local_irq_save(flags); - /* Update the statistics from the device registers. */ - dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); - dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6); - local_irq_restore(flags); - - return &dev->stats; -} - -static void set_multicast_list(struct net_device *dev) -{ - struct net_local *lp = netdev_priv(dev); - - if(dev->flags&IFF_PROMISC) - { - lp->rx_mode = RX_ALL_ACCEPT; - } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) { - /* The multicast-accept list is initialized to accept-all, and we - rely on higher-level filtering for now. */ - lp->rx_mode = RX_MULTCAST_ACCEPT; - } - else - lp->rx_mode = 0; - - writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode); - - /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */ - writereg(dev, PP_RxCFG, lp->curr_rx_cfg | - (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0)); -} - - -static int set_mac_address(struct net_device *dev, void *addr) -{ - int i; - printk("%s: Setting MAC address to ", dev->name); - for (i = 0; i < 6; i++) - printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); - printk(".\n"); - /* set the Ethernet address */ - for (i=0; i < ETH_ALEN/2; i++) - writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); - - return 0; -} - -#ifdef MODULE - -static struct net_device *dev_cs89x0; -static int debug; - -module_param(debug, int, 0); -MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)"); -MODULE_LICENSE("GPL"); - -int __init -init_module(void) -{ - net_debug = debug; - dev_cs89x0 = mac89x0_probe(-1); - if (IS_ERR(dev_cs89x0)) { - printk(KERN_WARNING "mac89x0.c: No card found\n"); - return PTR_ERR(dev_cs89x0); - } - return 0; -} - -void -cleanup_module(void) -{ - unregister_netdev(dev_cs89x0); - nubus_writew(0, dev_cs89x0->base_addr + ADD_PORT); - free_netdev(dev_cs89x0); -} -#endif /* MODULE */ diff --git a/drivers/net/ethernet/cirrus/Kconfig b/drivers/net/ethernet/cirrus/Kconfig index 6cbb81c..1f8648f 100644 --- a/drivers/net/ethernet/cirrus/Kconfig +++ b/drivers/net/ethernet/cirrus/Kconfig @@ -6,7 +6,7 @@ config NET_VENDOR_CIRRUS bool "Cirrus devices" default y depends on ISA || EISA || MACH_IXDP2351 || ARCH_IXDP2X01 \ - || MACH_MX31ADS || MACH_QQ2440 || (ARM && ARCH_EP93XX) + || MACH_MX31ADS || MACH_QQ2440 || (ARM && ARCH_EP93XX) || MAC ---help--- If you have a network (Ethernet) card belonging to this class, say Y and read the Ethernet-HOWTO, available from @@ -47,4 +47,16 @@ config EP93XX_ETH This is a driver for the ethernet hardware included in EP93xx CPUs. Say Y if you are building a kernel for EP93xx based devices. +config MAC89x0 + tristate "Macintosh CS89x0 based ethernet cards" + depends on MAC + ---help--- + Support for CS89x0 chipset based Ethernet cards. If you have a + Nubus or LC-PDS network (Ethernet) card of this type, say Y and + read the Ethernet-HOWTO, available from + . + + To compile this driver as a module, choose M here. This module will + be called mac89x0. + endif # NET_VENDOR_CIRRUS diff --git a/drivers/net/ethernet/cirrus/Makefile b/drivers/net/ethernet/cirrus/Makefile index 14bd77e..ca245e2 100644 --- a/drivers/net/ethernet/cirrus/Makefile +++ b/drivers/net/ethernet/cirrus/Makefile @@ -4,3 +4,4 @@ obj-$(CONFIG_CS89x0) += cs89x0.o obj-$(CONFIG_EP93XX_ETH) += ep93xx_eth.o +obj-$(CONFIG_MAC89x0) += mac89x0.o diff --git a/drivers/net/ethernet/cirrus/mac89x0.c b/drivers/net/ethernet/cirrus/mac89x0.c new file mode 100644 index 0000000..83781f3 --- /dev/null +++ b/drivers/net/ethernet/cirrus/mac89x0.c @@ -0,0 +1,634 @@ +/* mac89x0.c: A Crystal Semiconductor CS89[02]0 driver for linux. */ +/* + Written 1996 by Russell Nelson, with reference to skeleton.c + written 1993-1994 by Donald Becker. + + This software may be used and distributed according to the terms + of the GNU General Public License, incorporated herein by reference. + + The author may be reached at nelson@crynwr.com, Crynwr + Software, 11 Grant St., Potsdam, NY 13676 + + Changelog: + + Mike Cruse : mcruse@cti-ltd.com + : Changes for Linux 2.0 compatibility. + : Added dev_id parameter in net_interrupt(), + : request_irq() and free_irq(). Just NULL for now. + + Mike Cruse : Added MOD_INC_USE_COUNT and MOD_DEC_USE_COUNT macros + : in net_open() and net_close() so kerneld would know + : that the module is in use and wouldn't eject the + : driver prematurely. + + Mike Cruse : Rewrote init_module() and cleanup_module using 8390.c + : as an example. Disabled autoprobing in init_module(), + : not a good thing to do to other devices while Linux + : is running from all accounts. + + Alan Cox : Removed 1.2 support, added 2.1 extra counters. + + David Huggins-Daines + + Split this off into mac89x0.c, and gutted it of all parts which are + not relevant to the existing CS8900 cards on the Macintosh + (i.e. basically the Daynaport CS and LC cards). To be precise: + + * Removed all the media-detection stuff, because these cards are + TP-only. + + * Lobotomized the ISA interrupt bogosity, because these cards use + a hardwired NuBus interrupt and a magic ISAIRQ value in the card. + + * Basically eliminated everything not relevant to getting the + cards minimally functioning on the Macintosh. + + I might add that these cards are badly designed even from the Mac + standpoint, in that Dayna, in their infinite wisdom, used NuBus slot + I/O space and NuBus interrupts for these cards, but neglected to + provide anything even remotely resembling a NuBus ROM. Therefore we + have to probe for them in a brain-damaged ISA-like fashion. + + Arnaldo Carvalho de Melo - 11/01/2001 + check kmalloc and release the allocated memory on failure in + mac89x0_probe and in init_module + use local_irq_{save,restore}(flags) in net_get_stat, not just + local_irq_{dis,en}able() +*/ + +static char *version = +"cs89x0.c:v1.02 11/26/96 Russell Nelson \n"; + +/* ======================= configure the driver here ======================= */ + +/* use 0 for production, 1 for verification, >2 for debug */ +#ifndef NET_DEBUG +#define NET_DEBUG 0 +#endif + +/* ======================= end of configuration ======================= */ + + +/* Always include 'config.h' first in case the user wants to turn on + or override something. */ +#include + +/* + Sources: + + Crynwr packet driver epktisa. + + Crystal Semiconductor data sheets. + +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cs89x0.h" + +static unsigned int net_debug = NET_DEBUG; + +/* Information that need to be kept for each board. */ +struct net_local { + int chip_type; /* one of: CS8900, CS8920, CS8920M */ + char chip_revision; /* revision letter of the chip ('A'...) */ + int send_cmd; /* the propercommand used to send a packet. */ + int rx_mode; + int curr_rx_cfg; + int send_underrun; /* keep track of how many underruns in a row we get */ + struct sk_buff *skb; +}; + +/* Index to functions, as function prototypes. */ + +#if 0 +extern void reset_chip(struct net_device *dev); +#endif +static int net_open(struct net_device *dev); +static int net_send_packet(struct sk_buff *skb, struct net_device *dev); +static irqreturn_t net_interrupt(int irq, void *dev_id); +static void set_multicast_list(struct net_device *dev); +static void net_rx(struct net_device *dev); +static int net_close(struct net_device *dev); +static struct net_device_stats *net_get_stats(struct net_device *dev); +static int set_mac_address(struct net_device *dev, void *addr); + + +/* Example routines you must write ;->. */ +#define tx_done(dev) 1 + +/* For reading/writing registers ISA-style */ +static inline int +readreg_io(struct net_device *dev, int portno) +{ + nubus_writew(swab16(portno), dev->base_addr + ADD_PORT); + return swab16(nubus_readw(dev->base_addr + DATA_PORT)); +} + +static inline void +writereg_io(struct net_device *dev, int portno, int value) +{ + nubus_writew(swab16(portno), dev->base_addr + ADD_PORT); + nubus_writew(swab16(value), dev->base_addr + DATA_PORT); +} + +/* These are for reading/writing registers in shared memory */ +static inline int +readreg(struct net_device *dev, int portno) +{ + return swab16(nubus_readw(dev->mem_start + portno)); +} + +static inline void +writereg(struct net_device *dev, int portno, int value) +{ + nubus_writew(swab16(value), dev->mem_start + portno); +} + +static const struct net_device_ops mac89x0_netdev_ops = { + .ndo_open = net_open, + .ndo_stop = net_close, + .ndo_start_xmit = net_send_packet, + .ndo_get_stats = net_get_stats, + .ndo_set_rx_mode = set_multicast_list, + .ndo_set_mac_address = set_mac_address, + .ndo_validate_addr = eth_validate_addr, + .ndo_change_mtu = eth_change_mtu, +}; + +/* Probe for the CS8900 card in slot E. We won't bother looking + anywhere else until we have a really good reason to do so. */ +struct net_device * __init mac89x0_probe(int unit) +{ + struct net_device *dev; + static int once_is_enough; + struct net_local *lp; + static unsigned version_printed; + int i, slot; + unsigned rev_type = 0; + unsigned long ioaddr; + unsigned short sig; + int err = -ENODEV; + + if (!MACH_IS_MAC) + return ERR_PTR(-ENODEV); + + dev = alloc_etherdev(sizeof(struct net_local)); + if (!dev) + return ERR_PTR(-ENOMEM); + + if (unit >= 0) { + sprintf(dev->name, "eth%d", unit); + netdev_boot_setup_check(dev); + } + + if (once_is_enough) + goto out; + once_is_enough = 1; + + /* We might have to parameterize this later */ + slot = 0xE; + /* Get out now if there's a real NuBus card in slot E */ + if (nubus_find_slot(slot, NULL) != NULL) + goto out; + + /* The pseudo-ISA bits always live at offset 0x300 (gee, + wonder why...) */ + ioaddr = (unsigned long) + nubus_slot_addr(slot) | (((slot&0xf) << 20) + DEFAULTIOBASE); + { + unsigned long flags; + int card_present; + + local_irq_save(flags); + card_present = (hwreg_present((void*) ioaddr+4) && + hwreg_present((void*) ioaddr + DATA_PORT)); + local_irq_restore(flags); + + if (!card_present) + goto out; + } + + nubus_writew(0, ioaddr + ADD_PORT); + sig = nubus_readw(ioaddr + DATA_PORT); + if (sig != swab16(CHIP_EISA_ID_SIG)) + goto out; + + /* Initialize the net_device structure. */ + lp = netdev_priv(dev); + + /* Fill in the 'dev' fields. */ + dev->base_addr = ioaddr; + dev->mem_start = (unsigned long) + nubus_slot_addr(slot) | (((slot&0xf) << 20) + MMIOBASE); + dev->mem_end = dev->mem_start + 0x1000; + + /* Turn on shared memory */ + writereg_io(dev, PP_BusCTL, MEMORY_ON); + + /* get the chip type */ + rev_type = readreg(dev, PRODUCT_ID_ADD); + lp->chip_type = rev_type &~ REVISON_BITS; + lp->chip_revision = ((rev_type & REVISON_BITS) >> 8) + 'A'; + + /* Check the chip type and revision in order to set the correct send command + CS8920 revision C and CS8900 revision F can use the faster send. */ + lp->send_cmd = TX_AFTER_381; + if (lp->chip_type == CS8900 && lp->chip_revision >= 'F') + lp->send_cmd = TX_NOW; + if (lp->chip_type != CS8900 && lp->chip_revision >= 'C') + lp->send_cmd = TX_NOW; + + if (net_debug && version_printed++ == 0) + printk(version); + + printk(KERN_INFO "%s: cs89%c0%s rev %c found at %#8lx", + dev->name, + lp->chip_type==CS8900?'0':'2', + lp->chip_type==CS8920M?"M":"", + lp->chip_revision, + dev->base_addr); + + /* Try to read the MAC address */ + if ((readreg(dev, PP_SelfST) & (EEPROM_PRESENT | EEPROM_OK)) == 0) { + printk("\nmac89x0: No EEPROM, giving up now.\n"); + goto out1; + } else { + for (i = 0; i < ETH_ALEN; i += 2) { + /* Big-endian (why??!) */ + unsigned short s = readreg(dev, PP_IA + i); + dev->dev_addr[i] = s >> 8; + dev->dev_addr[i+1] = s & 0xff; + } + } + + dev->irq = SLOT2IRQ(slot); + + /* print the IRQ and ethernet address. */ + + printk(" IRQ %d ADDR %pM\n", dev->irq, dev->dev_addr); + + dev->netdev_ops = &mac89x0_netdev_ops; + + err = register_netdev(dev); + if (err) + goto out1; + return NULL; +out1: + nubus_writew(0, dev->base_addr + ADD_PORT); +out: + free_netdev(dev); + return ERR_PTR(err); +} + +#if 0 +/* This is useful for something, but I don't know what yet. */ +void __init reset_chip(struct net_device *dev) +{ + int reset_start_time; + + writereg(dev, PP_SelfCTL, readreg(dev, PP_SelfCTL) | POWER_ON_RESET); + + /* wait 30 ms */ + msleep_interruptible(30); + + /* Wait until the chip is reset */ + reset_start_time = jiffies; + while( (readreg(dev, PP_SelfST) & INIT_DONE) == 0 && jiffies - reset_start_time < 2) + ; +} +#endif + +/* Open/initialize the board. This is called (in the current kernel) + sometime after booting when the 'ifconfig' program is run. + + This routine should set everything up anew at each open, even + registers that "should" only need to be set once at boot, so that + there is non-reboot way to recover if something goes wrong. + */ +static int +net_open(struct net_device *dev) +{ + struct net_local *lp = netdev_priv(dev); + int i; + + /* Disable the interrupt for now */ + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) & ~ENABLE_IRQ); + + /* Grab the interrupt */ + if (request_irq(dev->irq, net_interrupt, 0, "cs89x0", dev)) + return -EAGAIN; + + /* Set up the IRQ - Apparently magic */ + if (lp->chip_type == CS8900) + writereg(dev, PP_CS8900_ISAINT, 0); + else + writereg(dev, PP_CS8920_ISAINT, 0); + + /* set the Ethernet address */ + for (i=0; i < ETH_ALEN/2; i++) + writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); + + /* Turn on both receive and transmit operations */ + writereg(dev, PP_LineCTL, readreg(dev, PP_LineCTL) | SERIAL_RX_ON | SERIAL_TX_ON); + + /* Receive only error free packets addressed to this card */ + lp->rx_mode = 0; + writereg(dev, PP_RxCTL, DEF_RX_ACCEPT); + + lp->curr_rx_cfg = RX_OK_ENBL | RX_CRC_ERROR_ENBL; + + writereg(dev, PP_RxCFG, lp->curr_rx_cfg); + + writereg(dev, PP_TxCFG, TX_LOST_CRS_ENBL | TX_SQE_ERROR_ENBL | TX_OK_ENBL | + TX_LATE_COL_ENBL | TX_JBR_ENBL | TX_ANY_COL_ENBL | TX_16_COL_ENBL); + + writereg(dev, PP_BufCFG, READY_FOR_TX_ENBL | RX_MISS_COUNT_OVRFLOW_ENBL | + TX_COL_COUNT_OVRFLOW_ENBL | TX_UNDERRUN_ENBL); + + /* now that we've got our act together, enable everything */ + writereg(dev, PP_BusCTL, readreg(dev, PP_BusCTL) | ENABLE_IRQ); + netif_start_queue(dev); + return 0; +} + +static int +net_send_packet(struct sk_buff *skb, struct net_device *dev) +{ + struct net_local *lp = netdev_priv(dev); + unsigned long flags; + + if (net_debug > 3) + printk("%s: sent %d byte packet of type %x\n", + dev->name, skb->len, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) + | skb->data[ETH_ALEN+ETH_ALEN+1]); + + /* keep the upload from being interrupted, since we + ask the chip to start transmitting before the + whole packet has been completely uploaded. */ + local_irq_save(flags); + netif_stop_queue(dev); + + /* initiate a transmit sequence */ + writereg(dev, PP_TxCMD, lp->send_cmd); + writereg(dev, PP_TxLength, skb->len); + + /* Test to see if the chip has allocated memory for the packet */ + if ((readreg(dev, PP_BusST) & READY_FOR_TX_NOW) == 0) { + /* Gasp! It hasn't. But that shouldn't happen since + we're waiting for TxOk, so return 1 and requeue this packet. */ + local_irq_restore(flags); + return NETDEV_TX_BUSY; + } + + /* Write the contents of the packet */ + skb_copy_from_linear_data(skb, (void *)(dev->mem_start + PP_TxFrame), + skb->len+1); + + local_irq_restore(flags); + dev_kfree_skb (skb); + + return NETDEV_TX_OK; +} + +/* The typical workload of the driver: + Handle the network interface interrupts. */ +static irqreturn_t net_interrupt(int irq, void *dev_id) +{ + struct net_device *dev = dev_id; + struct net_local *lp; + int ioaddr, status; + + if (dev == NULL) { + printk ("net_interrupt(): irq %d for unknown device.\n", irq); + return IRQ_NONE; + } + + ioaddr = dev->base_addr; + lp = netdev_priv(dev); + + /* we MUST read all the events out of the ISQ, otherwise we'll never + get interrupted again. As a consequence, we can't have any limit + on the number of times we loop in the interrupt handler. The + hardware guarantees that eventually we'll run out of events. Of + course, if you're on a slow machine, and packets are arriving + faster than you can read them off, you're screwed. Hasta la + vista, baby! */ + while ((status = swab16(nubus_readw(dev->base_addr + ISQ_PORT)))) { + if (net_debug > 4)printk("%s: event=%04x\n", dev->name, status); + switch(status & ISQ_EVENT_MASK) { + case ISQ_RECEIVER_EVENT: + /* Got a packet(s). */ + net_rx(dev); + break; + case ISQ_TRANSMITTER_EVENT: + dev->stats.tx_packets++; + netif_wake_queue(dev); + if ((status & TX_OK) == 0) + dev->stats.tx_errors++; + if (status & TX_LOST_CRS) + dev->stats.tx_carrier_errors++; + if (status & TX_SQE_ERROR) + dev->stats.tx_heartbeat_errors++; + if (status & TX_LATE_COL) + dev->stats.tx_window_errors++; + if (status & TX_16_COL) + dev->stats.tx_aborted_errors++; + break; + case ISQ_BUFFER_EVENT: + if (status & READY_FOR_TX) { + /* we tried to transmit a packet earlier, + but inexplicably ran out of buffers. + That shouldn't happen since we only ever + load one packet. Shrug. Do the right + thing anyway. */ + netif_wake_queue(dev); + } + if (status & TX_UNDERRUN) { + if (net_debug > 0) printk("%s: transmit underrun\n", dev->name); + lp->send_underrun++; + if (lp->send_underrun == 3) lp->send_cmd = TX_AFTER_381; + else if (lp->send_underrun == 6) lp->send_cmd = TX_AFTER_ALL; + } + break; + case ISQ_RX_MISS_EVENT: + dev->stats.rx_missed_errors += (status >> 6); + break; + case ISQ_TX_COL_EVENT: + dev->stats.collisions += (status >> 6); + break; + } + } + return IRQ_HANDLED; +} + +/* We have a good packet(s), get it/them out of the buffers. */ +static void +net_rx(struct net_device *dev) +{ + struct sk_buff *skb; + int status, length; + + status = readreg(dev, PP_RxStatus); + if ((status & RX_OK) == 0) { + dev->stats.rx_errors++; + if (status & RX_RUNT) + dev->stats.rx_length_errors++; + if (status & RX_EXTRA_DATA) + dev->stats.rx_length_errors++; + if ((status & RX_CRC_ERROR) && + !(status & (RX_EXTRA_DATA|RX_RUNT))) + /* per str 172 */ + dev->stats.rx_crc_errors++; + if (status & RX_DRIBBLE) + dev->stats.rx_frame_errors++; + return; + } + + length = readreg(dev, PP_RxLength); + /* Malloc up new buffer. */ + skb = alloc_skb(length, GFP_ATOMIC); + if (skb == NULL) { + printk("%s: Memory squeeze, dropping packet.\n", dev->name); + dev->stats.rx_dropped++; + return; + } + skb_put(skb, length); + + skb_copy_to_linear_data(skb, (void *)(dev->mem_start + PP_RxFrame), + length); + + if (net_debug > 3)printk("%s: received %d byte packet of type %x\n", + dev->name, length, + (skb->data[ETH_ALEN+ETH_ALEN] << 8) + | skb->data[ETH_ALEN+ETH_ALEN+1]); + + skb->protocol=eth_type_trans(skb,dev); + netif_rx(skb); + dev->stats.rx_packets++; + dev->stats.rx_bytes += length; +} + +/* The inverse routine to net_open(). */ +static int +net_close(struct net_device *dev) +{ + + writereg(dev, PP_RxCFG, 0); + writereg(dev, PP_TxCFG, 0); + writereg(dev, PP_BufCFG, 0); + writereg(dev, PP_BusCTL, 0); + + netif_stop_queue(dev); + + free_irq(dev->irq, dev); + + /* Update the statistics here. */ + + return 0; + +} + +/* Get the current statistics. This may be called with the card open or + closed. */ +static struct net_device_stats * +net_get_stats(struct net_device *dev) +{ + unsigned long flags; + + local_irq_save(flags); + /* Update the statistics from the device registers. */ + dev->stats.rx_missed_errors += (readreg(dev, PP_RxMiss) >> 6); + dev->stats.collisions += (readreg(dev, PP_TxCol) >> 6); + local_irq_restore(flags); + + return &dev->stats; +} + +static void set_multicast_list(struct net_device *dev) +{ + struct net_local *lp = netdev_priv(dev); + + if(dev->flags&IFF_PROMISC) + { + lp->rx_mode = RX_ALL_ACCEPT; + } else if ((dev->flags & IFF_ALLMULTI) || !netdev_mc_empty(dev)) { + /* The multicast-accept list is initialized to accept-all, and we + rely on higher-level filtering for now. */ + lp->rx_mode = RX_MULTCAST_ACCEPT; + } + else + lp->rx_mode = 0; + + writereg(dev, PP_RxCTL, DEF_RX_ACCEPT | lp->rx_mode); + + /* in promiscuous mode, we accept errored packets, so we have to enable interrupts on them also */ + writereg(dev, PP_RxCFG, lp->curr_rx_cfg | + (lp->rx_mode == RX_ALL_ACCEPT? (RX_CRC_ERROR_ENBL|RX_RUNT_ENBL|RX_EXTRA_DATA_ENBL) : 0)); +} + + +static int set_mac_address(struct net_device *dev, void *addr) +{ + int i; + printk("%s: Setting MAC address to ", dev->name); + for (i = 0; i < 6; i++) + printk(" %2.2x", dev->dev_addr[i] = ((unsigned char *)addr)[i]); + printk(".\n"); + /* set the Ethernet address */ + for (i=0; i < ETH_ALEN/2; i++) + writereg(dev, PP_IA+i*2, dev->dev_addr[i*2] | (dev->dev_addr[i*2+1] << 8)); + + return 0; +} + +#ifdef MODULE + +static struct net_device *dev_cs89x0; +static int debug; + +module_param(debug, int, 0); +MODULE_PARM_DESC(debug, "CS89[02]0 debug level (0-5)"); +MODULE_LICENSE("GPL"); + +int __init +init_module(void) +{ + net_debug = debug; + dev_cs89x0 = mac89x0_probe(-1); + if (IS_ERR(dev_cs89x0)) { + printk(KERN_WARNING "mac89x0.c: No card found\n"); + return PTR_ERR(dev_cs89x0); + } + return 0; +} + +void +cleanup_module(void) +{ + unregister_netdev(dev_cs89x0); + nubus_writew(0, dev_cs89x0->base_addr + ADD_PORT); + free_netdev(dev_cs89x0); +} +#endif /* MODULE */ -- cgit v0.10.2 From 501e89d3aef10f9a5b79137fbb0bcd5bf9cac2ac Mon Sep 17 00:00:00 2001 From: Dave Jones Date: Tue, 1 Nov 2011 16:26:44 +0000 Subject: x25: Fix NULL dereference in x25_recvmsg commit cb101ed2 in 3.0 introduced a bug in x25_recvmsg() When passed bogus junk from userspace, x25->neighbour can be NULL, as shown in this oops.. BUG: unable to handle kernel NULL pointer dereference at 000000000000001c IP: [] x25_recvmsg+0x4d/0x280 [x25] PGD 1015f3067 PUD 105072067 PMD 0 Oops: 0000 [#1] PREEMPT SMP DEBUG_PAGEALLOC CPU 0 Pid: 27928, comm: iknowthis Not tainted 3.1.0+ #2 Gigabyte Technology Co., Ltd. GA-MA78GM-S2H/GA-MA78GM-S2H RIP: 0010:[] [] x25_recvmsg+0x4d/0x280 [x25] RSP: 0018:ffff88010c0b7cc8 EFLAGS: 00010282 RAX: 0000000000000000 RBX: ffff88010c0b7d78 RCX: 0000000000000c02 RDX: ffff88010c0b7d78 RSI: ffff88011c93dc00 RDI: ffff880103f667b0 RBP: ffff88010c0b7d18 R08: 0000000000000000 R09: 0000000000000000 R10: 0000000000000000 R11: 0000000000000000 R12: ffff880103f667b0 R13: 0000000000000000 R14: 0000000000000000 R15: 0000000000000000 FS: 00007f479ce7f700(0000) GS:ffff88012a600000(0000) knlGS:0000000000000000 CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b CR2: 000000000000001c CR3: 000000010529e000 CR4: 00000000000006f0 DR0: 0000000000000000 DR1: 0000000000000000 DR2: 0000000000000000 DR3: 0000000000000000 DR6: 00000000ffff0ff0 DR7: 0000000000000400 Process iknowthis (pid: 27928, threadinfo ffff88010c0b6000, task ffff880103faa4f0) Stack: 0000000000000c02 0000000000000c02 ffff88010c0b7d18 ffffff958153cb37 ffffffff8153cb60 0000000000000c02 ffff88011c93dc00 0000000000000000 0000000000000c02 ffff88010c0b7e10 ffff88010c0b7de8 ffffffff815372c2 Call Trace: [] ? sock_update_classid+0xb0/0x180 [] sock_aio_read.part.10+0x142/0x150 [] ? inode_has_perm+0x62/0xa0 [] sock_aio_read+0x2d/0x40 [] do_sync_read+0xd2/0x110 [] ? security_file_permission+0x96/0xb0 [] ? rw_verify_area+0x61/0x100 [] vfs_read+0x16d/0x180 [] sys_read+0x4d/0x90 [] system_call_fastpath+0x16/0x1b Code: 8b 66 20 4c 8b 32 48 89 d3 48 89 4d b8 45 89 c7 c7 45 cc 95 ff ff ff 4d 85 e4 0f 84 ed 01 00 00 49 8b 84 24 18 05 00 00 4c 89 e7 78 1c 01 45 19 ed 31 f6 e8 d5 37 ff e0 41 0f b6 44 24 0e 41 Signed-off-by: Dave Jones Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/x25/af_x25.c b/net/x25/af_x25.c index 5f03e4e..3e16c6a 100644 --- a/net/x25/af_x25.c +++ b/net/x25/af_x25.c @@ -1261,14 +1261,19 @@ static int x25_recvmsg(struct kiocb *iocb, struct socket *sock, struct x25_sock *x25 = x25_sk(sk); struct sockaddr_x25 *sx25 = (struct sockaddr_x25 *)msg->msg_name; size_t copied; - int qbit, header_len = x25->neighbour->extended ? - X25_EXT_MIN_LEN : X25_STD_MIN_LEN; - + int qbit, header_len; struct sk_buff *skb; unsigned char *asmptr; int rc = -ENOTCONN; lock_sock(sk); + + if (x25->neighbour == NULL) + goto out; + + header_len = x25->neighbour->extended ? + X25_EXT_MIN_LEN : X25_STD_MIN_LEN; + /* * This works for seqpacket too. The receiver has ordered the queue for * us! We do one quick check first though -- cgit v0.10.2 From 0ad92ad03aa444b312bd318b0341011a8be09d13 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Tue, 1 Nov 2011 12:56:59 +0000 Subject: udp: fix a race in encap_rcv handling udp_queue_rcv_skb() has a possible race in encap_rcv handling, since this pointer can be changed anytime. We should use ACCESS_ONCE() to close the race. Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/ipv4/udp.c b/net/ipv4/udp.c index 131d8a7..ab0966d 100644 --- a/net/ipv4/udp.c +++ b/net/ipv4/udp.c @@ -1397,6 +1397,8 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) nf_reset(skb); if (up->encap_type) { + int (*encap_rcv)(struct sock *sk, struct sk_buff *skb); + /* * This is an encapsulation socket so pass the skb to * the socket's udp_encap_rcv() hook. Otherwise, just @@ -1409,11 +1411,11 @@ int udp_queue_rcv_skb(struct sock *sk, struct sk_buff *skb) */ /* if we're overly short, let UDP handle it */ - if (skb->len > sizeof(struct udphdr) && - up->encap_rcv != NULL) { + encap_rcv = ACCESS_ONCE(up->encap_rcv); + if (skb->len > sizeof(struct udphdr) && encap_rcv != NULL) { int ret; - ret = (*up->encap_rcv)(sk, skb); + ret = encap_rcv(sk, skb); if (ret <= 0) { UDP_INC_STATS_BH(sock_net(sk), UDP_MIB_INDATAGRAMS, -- cgit v0.10.2 From 2edcd4ca43df3c1d1d392753531cc73a53e709ba Mon Sep 17 00:00:00 2001 From: Stephen Rothwell Date: Wed, 2 Nov 2011 01:49:44 -0400 Subject: net: fix typo in drivers/net/ethernet/xilinx/ll_temac_main.c Commit 9e903e085262 ("net: add skb frag size accessors") used frag_size instead of skb_frag_size in this file. Fixes this build error: drivers/net/ethernet/xilinx/ll_temac_main.c: In function 'temac_start_xmit': drivers/net/ethernet/xilinx/ll_temac_main.c:717:3: error: implicit declaration of function 'frag_size' [-Werror=implicit-function-declaration] Signed-off-by: Stephen Rothwell Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/xilinx/ll_temac_main.c b/drivers/net/ethernet/xilinx/ll_temac_main.c index 4d1658e..caf3659 100644 --- a/drivers/net/ethernet/xilinx/ll_temac_main.c +++ b/drivers/net/ethernet/xilinx/ll_temac_main.c @@ -716,8 +716,8 @@ static int temac_start_xmit(struct sk_buff *skb, struct net_device *ndev) cur_p = &lp->tx_bd_v[lp->tx_bd_tail]; cur_p->phys = dma_map_single(ndev->dev.parent, skb_frag_address(frag), - frag_size(frag), DMA_TO_DEVICE); - cur_p->len = frag_size(frag); + skb_frag_size(frag), DMA_TO_DEVICE); + cur_p->len = skb_frag_size(frag); cur_p->app0 = 0; frag++; } -- cgit v0.10.2 From 34c9ef8bc66e21bdecb215b2fb7d93092468d27d Mon Sep 17 00:00:00 2001 From: Bruce Allan Date: Fri, 21 Oct 2011 04:33:47 +0000 Subject: e1000e: demote a debugging WARN to a debug log message This debugging message was recently added but it does not need to be as alarming as a WARN. Signed-off-by: Bruce Allan Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/e1000e/ich8lan.c b/drivers/net/ethernet/intel/e1000e/ich8lan.c index 6a17c62..e2a80a2 100644 --- a/drivers/net/ethernet/intel/e1000e/ich8lan.c +++ b/drivers/net/ethernet/intel/e1000e/ich8lan.c @@ -866,8 +866,7 @@ static s32 e1000_acquire_swflag_ich8lan(struct e1000_hw *hw) if (test_and_set_bit(__E1000_ACCESS_SHARED_RESOURCE, &hw->adapter->state)) { - WARN(1, "e1000e: %s: contention for Phy access\n", - hw->adapter->netdev->name); + e_dbg("contention for Phy access\n"); return -E1000_ERR_PHY; } -- cgit v0.10.2 From 243559f436f26b571ea3a4e70ff082892dc58f16 Mon Sep 17 00:00:00 2001 From: Jesse Brandeburg Date: Sat, 22 Oct 2011 05:18:10 +0000 Subject: e100: make sure vlan support isn't advertised on old adapters e100 parts don't support vlan offload but they generally do allow use of vlans in higher software layers via the 8021q module. That said, there are a couple of really old revisions of e100 hardware that don't even allow the longer frame sizes required for vlan use with standard MTU. Use the VLAN_CHALLENGED flag to prevent vlan binding to these devices. Reported-by: Michael Tokarev Signed-off-by: Jesse Brandeburg CC: Michael Tokarev CC: David Lamparter Tested-by: Aaron Brown Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/e100.c b/drivers/net/ethernet/intel/e100.c index ae17cd1..5a2fdf7 100644 --- a/drivers/net/ethernet/intel/e100.c +++ b/drivers/net/ethernet/intel/e100.c @@ -2810,6 +2810,10 @@ static int __devinit e100_probe(struct pci_dev *pdev, e100_get_defaults(nic); + /* D100 MAC doesn't allow rx of vlan packets with normal MTU */ + if (nic->mac < mac_82558_D101_A4) + netdev->features |= NETIF_F_VLAN_CHALLENGED; + /* locks must be initialized before calling hw_reset */ spin_lock_init(&nic->cb_lock); spin_lock_init(&nic->cmd_lock); -- cgit v0.10.2 From d5a0e3640c05b7d07c548f9f8f986dbb87cfad98 Mon Sep 17 00:00:00 2001 From: "Kantecki, Tomasz" Date: Mon, 17 Oct 2011 22:06:59 +0000 Subject: igb: Fix for I347AT4 PHY cable length unit detection The PHY cable length unit detection was not using the correct the correct PHY data variable for I347AT4. Signed-off-by: Tomasz Kantecki Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/igb/e1000_phy.c b/drivers/net/ethernet/intel/igb/e1000_phy.c index 7edf31e..b17d7c2 100644 --- a/drivers/net/ethernet/intel/igb/e1000_phy.c +++ b/drivers/net/ethernet/intel/igb/e1000_phy.c @@ -1687,7 +1687,7 @@ s32 igb_get_cable_length_m88_gen2(struct e1000_hw *hw) if (ret_val) goto out; - is_cm = !(phy_data & I347AT4_PCDC_CABLE_LENGTH_UNIT); + is_cm = !(phy_data2 & I347AT4_PCDC_CABLE_LENGTH_UNIT); /* Populate the phy structure with cable length in meters */ phy->min_cable_length = phy_data / (is_cm ? 100 : 1); -- cgit v0.10.2 From 232ef6bc451de2bc17c22fd116838cd89b94e1c1 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 19 Oct 2011 07:41:58 +0000 Subject: ixgbe: Fix link issues caused by a reset while interface is down Interface fails to obtain link on 82599 SFP in the following scenario: 1. Set advertised speed to GB: ethtool -s eth0 advertise 0x20 2. Bring interface down ip link set eth0 down 3. Issue any command that leads to a reset: ethtool -t eth0 4. Bring link back up: ip link set eth0 up Following patch makes sure that the driver flaps the Tx laser every time ixgbe_start_hw() is called, and not only when the speed is set. Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 09b8e88..b7abf43 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -6125,7 +6125,6 @@ static void ixgbe_sfp_link_config_subtask(struct ixgbe_adapter *adapter) autoneg = hw->phy.autoneg_advertised; if ((!autoneg) && (hw->mac.ops.get_link_capabilities)) hw->mac.ops.get_link_capabilities(hw, &autoneg, &negotiation); - hw->mac.autotry_restart = false; if (hw->mac.ops.setup_link) hw->mac.ops.setup_link(hw, autoneg, negotiation, true); -- cgit v0.10.2 From 93d3ce8fafb888702311fc8c5917faa4c25b8266 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Wed, 19 Oct 2011 07:59:55 +0000 Subject: ixgbe: fix disabling of Tx laser at probe register_netdev() calls ndo_set_features() which may result in HW reset which in turn will bring the laser back up. This patch moves ixgbe_laser_tx_disable() below register_netdev() in ixgbe_probe() to make sure laser is shut off on load. Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index b7abf43..2e9fd9d 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -7588,13 +7588,6 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, goto err_eeprom; } - /* power down the optics for multispeed fiber and 82599 SFP+ fiber */ - if (hw->mac.ops.disable_tx_laser && - ((hw->phy.multispeed_fiber) || - ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) && - (hw->mac.type == ixgbe_mac_82599EB)))) - hw->mac.ops.disable_tx_laser(hw); - setup_timer(&adapter->service_timer, &ixgbe_service_timer, (unsigned long) adapter); @@ -7692,6 +7685,13 @@ static int __devinit ixgbe_probe(struct pci_dev *pdev, if (err) goto err_register; + /* power down the optics for multispeed fiber and 82599 SFP+ fiber */ + if (hw->mac.ops.disable_tx_laser && + ((hw->phy.multispeed_fiber) || + ((hw->mac.ops.get_media_type(hw) == ixgbe_media_type_fiber) && + (hw->mac.type == ixgbe_mac_82599EB)))) + hw->mac.ops.disable_tx_laser(hw); + /* carrier off reporting is important to ethtool even BEFORE open */ netif_carrier_off(netdev); -- cgit v0.10.2 From b120818e652965669d3f1abaeaa5c3ccdfb28126 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Sat, 15 Oct 2011 05:00:10 +0000 Subject: ixgbe: fix smatch splat due to missing NULL check ixgbe_ieee_ets and ixgbe_ieee_pfc are intialized at the same time. Do a check for both before configuring IEEE802.1Qaz. Also max_frame was causing a sparse warning resolved here as well. Reported-by: Dan Carpenter Signed-off-by: John Fastabend Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c index 2e9fd9d..8ef92d1 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c @@ -3345,34 +3345,25 @@ static void ixgbe_configure_dcb(struct ixgbe_adapter *adapter) hw->mac.ops.set_vfta(&adapter->hw, 0, 0, true); - /* reconfigure the hardware */ - if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE) { #ifdef IXGBE_FCOE - if (adapter->netdev->features & NETIF_F_FCOE_MTU) - max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE); + if (adapter->netdev->features & NETIF_F_FCOE_MTU) + max_frame = max(max_frame, IXGBE_FCOE_JUMBO_FRAME_SIZE); #endif + + /* reconfigure the hardware */ + if (adapter->dcbx_cap & DCB_CAP_DCBX_VER_CEE) { ixgbe_dcb_calculate_tc_credits(hw, &adapter->dcb_cfg, max_frame, DCB_TX_CONFIG); ixgbe_dcb_calculate_tc_credits(hw, &adapter->dcb_cfg, max_frame, DCB_RX_CONFIG); ixgbe_dcb_hw_config(hw, &adapter->dcb_cfg); - } else { - struct net_device *dev = adapter->netdev; - - if (adapter->ixgbe_ieee_ets) { - struct ieee_ets *ets = adapter->ixgbe_ieee_ets; - int max_frame = dev->mtu + ETH_HLEN + ETH_FCS_LEN; - - ixgbe_dcb_hw_ets(&adapter->hw, ets, max_frame); - } - - if (adapter->ixgbe_ieee_pfc) { - struct ieee_pfc *pfc = adapter->ixgbe_ieee_pfc; - u8 *prio_tc = adapter->ixgbe_ieee_ets->prio_tc; - - ixgbe_dcb_hw_pfc_config(&adapter->hw, pfc->pfc_en, - prio_tc); - } + } else if (adapter->ixgbe_ieee_ets && adapter->ixgbe_ieee_pfc) { + ixgbe_dcb_hw_ets(&adapter->hw, + adapter->ixgbe_ieee_ets, + max_frame); + ixgbe_dcb_hw_pfc_config(&adapter->hw, + adapter->ixgbe_ieee_pfc->pfc_en, + adapter->ixgbe_ieee_ets->prio_tc); } /* Enable RSS Hash per TC */ -- cgit v0.10.2 From 9487dc844054e1fc691fb82f4e19da337e2ca35e Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Fri, 21 Oct 2011 07:55:15 +0000 Subject: ixgbe: Fix compiler warnings Wrap SR-IOV specific functions in CONFIG_PCI_IOV to avoid compiler warnings. Signed-off-by: Greg Rose Tested-by: Sibai Li Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h index 5a7e1eb..4a5d889 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.h @@ -42,10 +42,12 @@ int ixgbe_ndo_set_vf_spoofchk(struct net_device *netdev, int vf, bool setting); int ixgbe_ndo_get_vf_config(struct net_device *netdev, int vf, struct ifla_vf_info *ivi); void ixgbe_check_vf_rate_limit(struct ixgbe_adapter *adapter); +#ifdef CONFIG_PCI_IOV void ixgbe_disable_sriov(struct ixgbe_adapter *adapter); void ixgbe_enable_sriov(struct ixgbe_adapter *adapter, const struct ixgbe_info *ii); int ixgbe_check_vf_assignment(struct ixgbe_adapter *adapter); +#endif #endif /* _IXGBE_SRIOV_H_ */ -- cgit v0.10.2 From 331bcf45feb76d507a769d9d3b26ff5626804117 Mon Sep 17 00:00:00 2001 From: Emil Tantilov Date: Sat, 22 Oct 2011 05:21:32 +0000 Subject: ixgbe: fix reading of the buffer returned by the firmware This patch fixes some issues found in the buffer read portion of ixgbe_host_interface_command() - use `bi` as the buffer index counter instead of `i` - add conversion to native cpu byte ordering on register read - fix conversion from bytes to dword - use dword_len instead of buf_len when reading the register Signed-off-by: Emil Tantilov Tested-by: Phil Schmitt Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c index 834f044..f1365fe 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_common.c @@ -3344,7 +3344,7 @@ static u8 ixgbe_calculate_checksum(u8 *buffer, u32 length) static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, u32 length) { - u32 hicr, i; + u32 hicr, i, bi; u32 hdr_size = sizeof(struct ixgbe_hic_hdr); u8 buf_len, dword_len; @@ -3398,9 +3398,9 @@ static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, dword_len = hdr_size >> 2; /* first pull in the header so we know the buffer length */ - for (i = 0; i < dword_len; i++) { - buffer[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, i); - le32_to_cpus(&buffer[i]); + for (bi = 0; bi < dword_len; bi++) { + buffer[bi] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, bi); + le32_to_cpus(&buffer[bi]); } /* If there is any thing in data position pull it in */ @@ -3414,12 +3414,14 @@ static s32 ixgbe_host_interface_command(struct ixgbe_hw *hw, u32 *buffer, goto out; } - /* Calculate length in DWORDs, add one for odd lengths */ - dword_len = (buf_len + 1) >> 2; + /* Calculate length in DWORDs, add 3 for odd lengths */ + dword_len = (buf_len + 3) >> 2; - /* Pull in the rest of the buffer (i is where we left off)*/ - for (; i < buf_len; i++) - buffer[i] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, i); + /* Pull in the rest of the buffer (bi is where we left off)*/ + for (; bi <= dword_len; bi++) { + buffer[bi] = IXGBE_READ_REG_ARRAY(hw, IXGBE_FLEX_MNG, bi); + le32_to_cpus(&buffer[bi]); + } out: return ret_val; -- cgit v0.10.2 From 8599e251b3dd18c7bcb342d5b4acecc420f43606 Mon Sep 17 00:00:00 2001 From: John Fastabend Date: Wed, 19 Oct 2011 08:48:49 +0000 Subject: ixgbe: DCB, return max for IEEE traffic classes Returning the max traffic classes on get requests simplifies user space configurations because applications will know explicitly how many traffic classes can be used. Typical switch implementations use 2 or 3 traffic classes so this not seen often today. And user space can learn the number of traffic classes by return codes but this allows user space to configure ixgbe correctly at the start. Signed-off-by: John Fastabend Tested-by: Ross Brattain Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c index 3631d63..33b93ff 100644 --- a/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c +++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_dcb_nl.c @@ -561,11 +561,12 @@ static int ixgbe_dcbnl_ieee_getets(struct net_device *dev, struct ixgbe_adapter *adapter = netdev_priv(dev); struct ieee_ets *my_ets = adapter->ixgbe_ieee_ets; + ets->ets_cap = adapter->dcb_cfg.num_tcs.pg_tcs; + /* No IEEE PFC settings available */ if (!my_ets) - return -EINVAL; + return 0; - ets->ets_cap = adapter->dcb_cfg.num_tcs.pg_tcs; ets->cbs = my_ets->cbs; memcpy(ets->tc_tx_bw, my_ets->tc_tx_bw, sizeof(ets->tc_tx_bw)); memcpy(ets->tc_rx_bw, my_ets->tc_rx_bw, sizeof(ets->tc_rx_bw)); @@ -621,11 +622,12 @@ static int ixgbe_dcbnl_ieee_getpfc(struct net_device *dev, struct ieee_pfc *my_pfc = adapter->ixgbe_ieee_pfc; int i; + pfc->pfc_cap = adapter->dcb_cfg.num_tcs.pfc_tcs; + /* No IEEE PFC settings available */ if (!my_pfc) - return -EINVAL; + return 0; - pfc->pfc_cap = adapter->dcb_cfg.num_tcs.pfc_tcs; pfc->pfc_en = my_pfc->pfc_en; pfc->mbc = my_pfc->mbc; pfc->delay = my_pfc->delay; -- cgit v0.10.2 From c1a7e1ebc17a9243d99ba0432d1138d74114dea7 Mon Sep 17 00:00:00 2001 From: Greg Rose Date: Thu, 20 Oct 2011 04:14:49 +0000 Subject: ixgbevf: Update release version Signed-off-by: Greg Rose Tested-by: Sibai Li Signed-off-by: Jeff Kirsher diff --git a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c index 5e92cc2..4c8e199 100644 --- a/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c +++ b/drivers/net/ethernet/intel/ixgbevf/ixgbevf_main.c @@ -54,7 +54,7 @@ char ixgbevf_driver_name[] = "ixgbevf"; static const char ixgbevf_driver_string[] = "Intel(R) 10 Gigabit PCI Express Virtual Function Network Driver"; -#define DRV_VERSION "2.1.0-k" +#define DRV_VERSION "2.2.0-k" const char ixgbevf_driver_version[] = DRV_VERSION; static char ixgbevf_copyright[] = "Copyright (c) 2009 - 2010 Intel Corporation."; -- cgit v0.10.2 From e2e210c0238eb7073e07af503ae743fa53977120 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Nov 2011 22:47:44 +0000 Subject: l2tp: fix race in l2tp_recv_dequeue() Misha Labjuk reported panics occurring in l2tp_recv_dequeue() If we release reorder_q.lock, we must not keep a dangling pointer (tmp), since another thread could manipulate reorder_q. Instead we must restart the scan at beginning of list. Reported-by: Misha Labjuk Tested-by: Misha Labjuk Signed-off-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/l2tp/l2tp_core.c b/net/l2tp/l2tp_core.c index 34b2dde..bf8d50c 100644 --- a/net/l2tp/l2tp_core.c +++ b/net/l2tp/l2tp_core.c @@ -397,6 +397,7 @@ static void l2tp_recv_dequeue(struct l2tp_session *session) * expect to send up next, dequeue it and any other * in-sequence packets behind it. */ +start: spin_lock_bh(&session->reorder_q.lock); skb_queue_walk_safe(&session->reorder_q, skb, tmp) { if (time_after(jiffies, L2TP_SKB_CB(skb)->expires)) { @@ -433,7 +434,7 @@ static void l2tp_recv_dequeue(struct l2tp_session *session) */ spin_unlock_bh(&session->reorder_q.lock); l2tp_recv_dequeue_skb(session, skb); - spin_lock_bh(&session->reorder_q.lock); + goto start; } out: -- cgit v0.10.2 From 918eb39962dfff9490a43cd08176b962cacc7978 Mon Sep 17 00:00:00 2001 From: Eric Dumazet Date: Wed, 2 Nov 2011 12:42:56 +0000 Subject: net: add missing bh_unlock_sock() calls Simon Kirby reported lockdep warnings and following messages : [104661.897577] huh, entered softirq 3 NET_RX ffffffff81613740 preempt_count 00000101, exited with 00000102? [104661.923653] huh, entered softirq 3 NET_RX ffffffff81613740 preempt_count 00000101, exited with 00000102? Problem comes from commit 0e734419 (ipv4: Use inet_csk_route_child_sock() in DCCP and TCP.) If inet_csk_route_child_sock() returns NULL, we should release socket lock before freeing it. Another lock imbalance exists if __inet_inherit_port() returns an error since commit 093d282321da ( tproxy: fix hash locking issue when using port redirection in __inet_inherit_port()) a backport is also needed for >= 2.6.37 kernels. Reported-by: Simon Kirby Signed-off-by: Eric Dumazet Tested-by: Eric Dumazet CC: Balazs Scheidler CC: KOVACS Krisztian Reviewed-by: Thomas Gleixner Tested-by: Simon Kirby Signed-off-by: David S. Miller diff --git a/net/dccp/ipv4.c b/net/dccp/ipv4.c index 332639b..90a919a 100644 --- a/net/dccp/ipv4.c +++ b/net/dccp/ipv4.c @@ -433,6 +433,7 @@ exit: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return NULL; put_and_exit: + bh_unlock_sock(newsk); sock_put(newsk); goto exit; } diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c index 939c55e..a744315 100644 --- a/net/ipv4/tcp_ipv4.c +++ b/net/ipv4/tcp_ipv4.c @@ -1510,6 +1510,7 @@ exit: NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_LISTENDROPS); return NULL; put_and_exit: + bh_unlock_sock(newsk); sock_put(newsk); goto exit; } -- cgit v0.10.2 From bc417e30f8dff6e8657005c4317cd71239e53375 Mon Sep 17 00:00:00 2001 From: Tony Lindgren Date: Wed, 2 Nov 2011 13:40:28 +0000 Subject: net: Add back alignment for size for __alloc_skb Commit 87fb4b7b533073eeeaed0b6bf7c2328995f6c075 (net: more accurate skb truesize) changed the alignment of size. This can cause problems at least on some machines with NFS root: Unhandled fault: alignment exception (0x801) at 0xc183a43a Internal error: : 801 [#1] PREEMPT Modules linked in: CPU: 0 Not tainted (3.1.0-08784-g5eeee4a #733) pc : [] lr : [] psr: 60000013 sp : c180fef8 ip : 00000000 fp : c181f580 r10: 00000000 r9 : c044b28c r8 : 00000001 r7 : c183a3a0 r6 : c1835be0 r5 : c183a412 r4 : 000001f2 r3 : 00000000 r2 : 00000000 r1 : ffffffe6 r0 : c183a43a Flags: nZCv IRQs on FIQs on Mode SVC_32 ISA ARM Segment kernel Control: 0005317f Table: 10004000 DAC: 00000017 Process swapper (pid: 1, stack limit = 0xc180e270) Stack: (0xc180fef8 to 0xc1810000) fee0: 00000024 00000000 ff00: 00000000 c183b9c0 c183b8e0 c044b28c c0507ccc c019dfc4 c180ff2c c0503cf8 ff20: c180ff4c c180ff4c 00000000 c1835420 c182c740 c18349c0 c05233c0 00000000 ff40: 00000000 c00e6bb8 c180e000 00000000 c04dd82c c0507e7c c050cc18 c183b9c0 ff60: c05233c0 00000000 00000000 c01f34f4 c0430d70 c019d364 c04dd898 c04dd898 ff80: c04dd82c c0507e7c c180e000 00000000 c04c584c c01f4918 c04dd898 c04dd82c ffa0: c04ddd28 c180e000 00000000 c0008758 c181fa60 3231d82c 00000037 00000000 ffc0: 00000000 c04dd898 c04dd82c c04ddd28 00000013 00000000 00000000 00000000 ffe0: 00000000 c04b2224 00000000 c04b21a0 c001056c c001056c 00000000 00000000 Function entered at [] from [] Function entered at [] from [] Function entered at [] from [] Function entered at [] from [] Function entered at [] from [] Function entered at [] from [] Code: e1a00005 e3a01028 ebfa7cb0 e35a0000 (e5858028) Here PC is at __alloc_skb and &shinfo->dataref is unaligned because skb->end can be unaligned without this patch. As explained by Eric Dumazet , this happens only with SLOB, and not with SLAB or SLUB: * Eric Dumazet [111102 15:56]: > > Your patch is absolutely needed, I completely forgot about SLOB :( > > since, kmalloc(386) on SLOB gives exactly ksize=386 bytes, not nearest > power of two. > > [ 60.305763] malloc(size=385)->ffff880112c11e38 ksize=386 -> nsize=2 > [ 60.305921] malloc(size=385)->ffff88007c92ce28 ksize=386 -> nsize=2 > [ 60.306898] malloc(size=656)->ffff88007c44ad28 ksize=656 -> nsize=272 > [ 60.325385] malloc(size=656)->ffff88007c575868 ksize=656 -> nsize=272 > [ 60.325531] malloc(size=656)->ffff88011c777230 ksize=656 -> nsize=272 > [ 60.325701] malloc(size=656)->ffff880114011008 ksize=656 -> nsize=272 > [ 60.346716] malloc(size=385)->ffff880114142008 ksize=386 -> nsize=2 > [ 60.346900] malloc(size=385)->ffff88011c777690 ksize=386 -> nsize=2 Signed-off-by: Tony Lindgren Acked-by: Eric Dumazet Signed-off-by: David S. Miller diff --git a/net/core/skbuff.c b/net/core/skbuff.c index ca4db40..18a3ceb 100644 --- a/net/core/skbuff.c +++ b/net/core/skbuff.c @@ -189,6 +189,7 @@ struct sk_buff *__alloc_skb(unsigned int size, gfp_t gfp_mask, * aligned memory blocks, unless SLUB/SLAB debug is enabled. * Both skb->head and skb_shared_info are cache line aligned. */ + size = SKB_DATA_ALIGN(size); size += SKB_DATA_ALIGN(sizeof(struct skb_shared_info)); data = kmalloc_node_track_caller(size, gfp_mask, node); if (!data) -- cgit v0.10.2 From c49b82da1f6649b76acbabc7940ddb53a00bdfcc Mon Sep 17 00:00:00 2001 From: Oliver Hartkopp Date: Wed, 2 Nov 2011 10:55:13 +0000 Subject: MAINTAINERS: Add can-gw include to maintained files Commit c1aabdf379bc2feeb0df7057ed5bad96f492133e (can-gw: add netlink based CAN routing) added a new include file that's neither referenced by any of the CAN maintainers. Signed-off-by: Oliver Hartkopp Signed-off-by: David S. Miller diff --git a/MAINTAINERS b/MAINTAINERS index 8edf72b..a618408 100644 --- a/MAINTAINERS +++ b/MAINTAINERS @@ -1703,6 +1703,7 @@ F: include/linux/can.h F: include/linux/can/core.h F: include/linux/can/bcm.h F: include/linux/can/raw.h +F: include/linux/can/gw.h CAN NETWORK DRIVERS M: Wolfgang Grandegger -- cgit v0.10.2 From eea49cc9009767dfbafd673ee577854454b52e0d Mon Sep 17 00:00:00 2001 From: Olof Johansson Date: Wed, 2 Nov 2011 11:00:49 +0000 Subject: af_packet: de-inline some helper functions This popped some compiler errors due to mismatched prototypes. Just remove most manual inlines, the compiler should be able to figure out what makes sense to inline and not. net/packet/af_packet.c:252: warning: 'prb_curr_blk_in_use' declared inline after being called net/packet/af_packet.c:252: warning: previous declaration of 'prb_curr_blk_in_use' was here net/packet/af_packet.c:258: warning: 'prb_queue_frozen' declared inline after being called net/packet/af_packet.c:258: warning: previous declaration of 'prb_queue_frozen' was here net/packet/af_packet.c:248: warning: 'packet_previous_frame' declared inline after being called net/packet/af_packet.c:248: warning: previous declaration of 'packet_previous_frame' was here net/packet/af_packet.c:251: warning: 'packet_increment_head' declared inline after being called net/packet/af_packet.c:251: warning: previous declaration of 'packet_increment_head' was here Signed-off-by: Olof Johansson Cc: Chetan Loke Signed-off-by: David S. Miller diff --git a/net/packet/af_packet.c b/net/packet/af_packet.c index 03bb45a..82a6f34 100644 --- a/net/packet/af_packet.c +++ b/net/packet/af_packet.c @@ -335,7 +335,7 @@ struct packet_skb_cb { (((x)->kactive_blk_num < ((x)->knum_blocks-1)) ? \ ((x)->kactive_blk_num+1) : 0) -static inline struct packet_sock *pkt_sk(struct sock *sk) +static struct packet_sock *pkt_sk(struct sock *sk) { return (struct packet_sock *)sk; } @@ -477,7 +477,7 @@ static void *packet_lookup_frame(struct packet_sock *po, return h.raw; } -static inline void *packet_current_frame(struct packet_sock *po, +static void *packet_current_frame(struct packet_sock *po, struct packet_ring_buffer *rb, int status) { @@ -715,7 +715,7 @@ out: spin_unlock(&po->sk.sk_receive_queue.lock); } -static inline void prb_flush_block(struct tpacket_kbdq_core *pkc1, +static void prb_flush_block(struct tpacket_kbdq_core *pkc1, struct tpacket_block_desc *pbd1, __u32 status) { /* Flush everything minus the block header */ @@ -793,7 +793,7 @@ static void prb_close_block(struct tpacket_kbdq_core *pkc1, pkc1->kactive_blk_num = GET_NEXT_PRB_BLK_NUM(pkc1); } -static inline void prb_thaw_queue(struct tpacket_kbdq_core *pkc) +static void prb_thaw_queue(struct tpacket_kbdq_core *pkc) { pkc->reset_pending_on_curr_blk = 0; } @@ -869,7 +869,7 @@ static void prb_open_block(struct tpacket_kbdq_core *pkc1, * case and __packet_lookup_frame_in_block will check if block-0 * is free and can now be re-used. */ -static inline void prb_freeze_queue(struct tpacket_kbdq_core *pkc, +static void prb_freeze_queue(struct tpacket_kbdq_core *pkc, struct packet_sock *po) { pkc->reset_pending_on_curr_blk = 1; @@ -940,36 +940,36 @@ static void prb_retire_current_block(struct tpacket_kbdq_core *pkc, BUG(); } -static inline int prb_curr_blk_in_use(struct tpacket_kbdq_core *pkc, +static int prb_curr_blk_in_use(struct tpacket_kbdq_core *pkc, struct tpacket_block_desc *pbd) { return TP_STATUS_USER & BLOCK_STATUS(pbd); } -static inline int prb_queue_frozen(struct tpacket_kbdq_core *pkc) +static int prb_queue_frozen(struct tpacket_kbdq_core *pkc) { return pkc->reset_pending_on_curr_blk; } -static inline void prb_clear_blk_fill_status(struct packet_ring_buffer *rb) +static void prb_clear_blk_fill_status(struct packet_ring_buffer *rb) { struct tpacket_kbdq_core *pkc = GET_PBDQC_FROM_RB(rb); atomic_dec(&pkc->blk_fill_in_prog); } -static inline void prb_fill_rxhash(struct tpacket_kbdq_core *pkc, +static void prb_fill_rxhash(struct tpacket_kbdq_core *pkc, struct tpacket3_hdr *ppd) { ppd->hv1.tp_rxhash = skb_get_rxhash(pkc->skb); } -static inline void prb_clear_rxhash(struct tpacket_kbdq_core *pkc, +static void prb_clear_rxhash(struct tpacket_kbdq_core *pkc, struct tpacket3_hdr *ppd) { ppd->hv1.tp_rxhash = 0; } -static inline void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc, +static void prb_fill_vlan_info(struct tpacket_kbdq_core *pkc, struct tpacket3_hdr *ppd) { if (vlan_tx_tag_present(pkc->skb)) { @@ -991,7 +991,7 @@ static void prb_run_all_ft_ops(struct tpacket_kbdq_core *pkc, prb_clear_rxhash(pkc, ppd); } -static inline void prb_fill_curr_block(char *curr, +static void prb_fill_curr_block(char *curr, struct tpacket_kbdq_core *pkc, struct tpacket_block_desc *pbd, unsigned int len) @@ -1071,7 +1071,7 @@ static void *__packet_lookup_frame_in_block(struct packet_sock *po, return NULL; } -static inline void *packet_current_rx_frame(struct packet_sock *po, +static void *packet_current_rx_frame(struct packet_sock *po, struct sk_buff *skb, int status, unsigned int len) { @@ -1091,7 +1091,7 @@ static inline void *packet_current_rx_frame(struct packet_sock *po, } } -static inline void *prb_lookup_block(struct packet_sock *po, +static void *prb_lookup_block(struct packet_sock *po, struct packet_ring_buffer *rb, unsigned int previous, int status) @@ -1104,7 +1104,7 @@ static inline void *prb_lookup_block(struct packet_sock *po, return pbd; } -static inline int prb_previous_blk_num(struct packet_ring_buffer *rb) +static int prb_previous_blk_num(struct packet_ring_buffer *rb) { unsigned int prev; if (rb->prb_bdqc.kactive_blk_num) @@ -1115,7 +1115,7 @@ static inline int prb_previous_blk_num(struct packet_ring_buffer *rb) } /* Assumes caller has held the rx_queue.lock */ -static inline void *__prb_previous_block(struct packet_sock *po, +static void *__prb_previous_block(struct packet_sock *po, struct packet_ring_buffer *rb, int status) { @@ -1123,7 +1123,7 @@ static inline void *__prb_previous_block(struct packet_sock *po, return prb_lookup_block(po, rb, previous, status); } -static inline void *packet_previous_rx_frame(struct packet_sock *po, +static void *packet_previous_rx_frame(struct packet_sock *po, struct packet_ring_buffer *rb, int status) { @@ -1133,7 +1133,7 @@ static inline void *packet_previous_rx_frame(struct packet_sock *po, return __prb_previous_block(po, rb, status); } -static inline void packet_increment_rx_head(struct packet_sock *po, +static void packet_increment_rx_head(struct packet_sock *po, struct packet_ring_buffer *rb) { switch (po->tp_version) { @@ -1148,7 +1148,7 @@ static inline void packet_increment_rx_head(struct packet_sock *po, } } -static inline void *packet_previous_frame(struct packet_sock *po, +static void *packet_previous_frame(struct packet_sock *po, struct packet_ring_buffer *rb, int status) { @@ -1156,7 +1156,7 @@ static inline void *packet_previous_frame(struct packet_sock *po, return packet_lookup_frame(po, rb, previous, status); } -static inline void packet_increment_head(struct packet_ring_buffer *buff) +static void packet_increment_head(struct packet_ring_buffer *buff) { buff->head = buff->head != buff->frame_max ? buff->head+1 : 0; } @@ -1558,7 +1558,7 @@ out_free: return err; } -static inline unsigned int run_filter(const struct sk_buff *skb, +static unsigned int run_filter(const struct sk_buff *skb, const struct sock *sk, unsigned int res) { @@ -2167,10 +2167,10 @@ out: return err; } -static inline struct sk_buff *packet_alloc_skb(struct sock *sk, size_t prepad, - size_t reserve, size_t len, - size_t linear, int noblock, - int *err) +static struct sk_buff *packet_alloc_skb(struct sock *sk, size_t prepad, + size_t reserve, size_t len, + size_t linear, int noblock, + int *err) { struct sk_buff *skb; @@ -3494,7 +3494,7 @@ static void free_pg_vec(struct pgv *pg_vec, unsigned int order, kfree(pg_vec); } -static inline char *alloc_one_pg_vec_page(unsigned long order) +static char *alloc_one_pg_vec_page(unsigned long order) { char *buffer = NULL; gfp_t gfp_flags = GFP_KERNEL | __GFP_COMP | -- cgit v0.10.2 From 016f97b11b3c7fe834260150d0f9cb36d06b2eb8 Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Thu, 3 Nov 2011 01:49:13 +0000 Subject: be2net: Fix endian issue in RX filter command Use cpu_to_le32() for mcast_num field in RX filter command as this field is of type u32. Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 824b8e6..bd8332c 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1540,7 +1540,7 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) req->if_flags_mask = req->if_flags = cpu_to_le32(BE_IF_FLAGS_MULTICAST); - req->mcast_num = cpu_to_le16(netdev_mc_count(adapter->netdev)); + req->mcast_num = cpu_to_le32(netdev_mc_count(adapter->netdev)); netdev_for_each_mc_addr(ha, adapter->netdev) memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN); } -- cgit v0.10.2 From 1610c79f1e9545d0a64dc6bb4f9affdfcf1d5726 Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Thu, 3 Nov 2011 01:49:27 +0000 Subject: be2net: Fix disabling multicast promiscous mode If user tries to disable multicast promiscous mode, the adapter remains in this mode as resetting the multicast promiscous mode was missing in RX filter command. Fixed this. Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index bd8332c..03fe7cd 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -1540,6 +1540,13 @@ int be_cmd_rx_filter(struct be_adapter *adapter, u32 flags, u32 value) req->if_flags_mask = req->if_flags = cpu_to_le32(BE_IF_FLAGS_MULTICAST); + + /* Reset mcast promisc mode if already set by setting mask + * and not setting flags field + */ + req->if_flags_mask |= + cpu_to_le32(BE_IF_FLAGS_MCAST_PROMISCUOUS); + req->mcast_num = cpu_to_le32(netdev_mc_count(adapter->netdev)); netdev_for_each_mc_addr(ha, adapter->netdev) memcpy(req->mcast_mac[i++].byte, ha->addr, ETH_ALEN); -- cgit v0.10.2 From 9372cacb300df3ee0a8be8a25bea15d16a95c583 Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Thu, 3 Nov 2011 01:49:55 +0000 Subject: be2net: Prevent CQ full condition for Lancer Indicate to HW that the CQ is cleaned up before posting new RX buffers. This prevents the HW to go into CQ full error condition. Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 2180497..30606f5 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1905,6 +1905,8 @@ loop_continue: be_rx_stats_update(rxo, rxcp); } + be_cq_notify(adapter, rx_cq->id, false, work_done); + /* Refill the queue */ if (work_done && atomic_read(&rxo->q.used) < RX_FRAGS_REFILL_WM) be_post_rx_frags(rxo, GFP_ATOMIC); @@ -1912,10 +1914,8 @@ loop_continue: /* All consumed */ if (work_done < budget) { napi_complete(napi); - be_cq_notify(adapter, rx_cq->id, true, work_done); - } else { - /* More to be consumed; continue with interrupts disabled */ - be_cq_notify(adapter, rx_cq->id, false, work_done); + /* Arm CQ */ + be_cq_notify(adapter, rx_cq->id, true, 0); } return work_done; } -- cgit v0.10.2 From e1cfb67acd5e890bbad695000d2c997bfb7f1756 Mon Sep 17 00:00:00 2001 From: Padmanabh Ratnakar Date: Thu, 3 Nov 2011 01:50:08 +0000 Subject: be2net: Add detect UE feature for Lancer Add code to detect UE in case of Lancer. Signed-off-by: Padmanabh Ratnakar Signed-off-by: David S. Miller diff --git a/drivers/net/ethernet/emulex/benet/be_cmds.c b/drivers/net/ethernet/emulex/benet/be_cmds.c index 03fe7cd..2c7b366 100644 --- a/drivers/net/ethernet/emulex/benet/be_cmds.c +++ b/drivers/net/ethernet/emulex/benet/be_cmds.c @@ -318,8 +318,7 @@ static int be_mbox_db_ready_wait(struct be_adapter *adapter, void __iomem *db) if (msecs > 4000) { dev_err(&adapter->pdev->dev, "mbox poll timed out\n"); - if (!lancer_chip(adapter)) - be_detect_dump_ue(adapter); + be_detect_dump_ue(adapter); return -1; } diff --git a/drivers/net/ethernet/emulex/benet/be_hw.h b/drivers/net/ethernet/emulex/benet/be_hw.h index fbc8a91..f2c89e3 100644 --- a/drivers/net/ethernet/emulex/benet/be_hw.h +++ b/drivers/net/ethernet/emulex/benet/be_hw.h @@ -48,6 +48,8 @@ /* Lancer SLIPORT_CONTROL SLIPORT_STATUS registers */ #define SLIPORT_STATUS_OFFSET 0x404 #define SLIPORT_CONTROL_OFFSET 0x408 +#define SLIPORT_ERROR1_OFFSET 0x40C +#define SLIPORT_ERROR2_OFFSET 0x410 #define SLIPORT_STATUS_ERR_MASK 0x80000000 #define SLIPORT_STATUS_RN_MASK 0x01000000 diff --git a/drivers/net/ethernet/emulex/benet/be_main.c b/drivers/net/ethernet/emulex/benet/be_main.c index 30606f5..e0aed18 100644 --- a/drivers/net/ethernet/emulex/benet/be_main.c +++ b/drivers/net/ethernet/emulex/benet/be_main.c @@ -1977,42 +1977,62 @@ static int be_poll_tx_mcc(struct napi_struct *napi, int budget) void be_detect_dump_ue(struct be_adapter *adapter) { - u32 ue_status_lo, ue_status_hi, ue_status_lo_mask, ue_status_hi_mask; + u32 ue_lo = 0, ue_hi = 0, ue_lo_mask = 0, ue_hi_mask = 0; + u32 sliport_status = 0, sliport_err1 = 0, sliport_err2 = 0; u32 i; - pci_read_config_dword(adapter->pdev, - PCICFG_UE_STATUS_LOW, &ue_status_lo); - pci_read_config_dword(adapter->pdev, - PCICFG_UE_STATUS_HIGH, &ue_status_hi); - pci_read_config_dword(adapter->pdev, - PCICFG_UE_STATUS_LOW_MASK, &ue_status_lo_mask); - pci_read_config_dword(adapter->pdev, - PCICFG_UE_STATUS_HI_MASK, &ue_status_hi_mask); + if (lancer_chip(adapter)) { + sliport_status = ioread32(adapter->db + SLIPORT_STATUS_OFFSET); + if (sliport_status & SLIPORT_STATUS_ERR_MASK) { + sliport_err1 = ioread32(adapter->db + + SLIPORT_ERROR1_OFFSET); + sliport_err2 = ioread32(adapter->db + + SLIPORT_ERROR2_OFFSET); + } + } else { + pci_read_config_dword(adapter->pdev, + PCICFG_UE_STATUS_LOW, &ue_lo); + pci_read_config_dword(adapter->pdev, + PCICFG_UE_STATUS_HIGH, &ue_hi); + pci_read_config_dword(adapter->pdev, + PCICFG_UE_STATUS_LOW_MASK, &ue_lo_mask); + pci_read_config_dword(adapter->pdev, + PCICFG_UE_STATUS_HI_MASK, &ue_hi_mask); - ue_status_lo = (ue_status_lo & (~ue_status_lo_mask)); - ue_status_hi = (ue_status_hi & (~ue_status_hi_mask)); + ue_lo = (ue_lo & (~ue_lo_mask)); + ue_hi = (ue_hi & (~ue_hi_mask)); + } - if (ue_status_lo || ue_status_hi) { + if (ue_lo || ue_hi || + sliport_status & SLIPORT_STATUS_ERR_MASK) { adapter->ue_detected = true; adapter->eeh_err = true; dev_err(&adapter->pdev->dev, "UE Detected!!\n"); } - if (ue_status_lo) { - for (i = 0; ue_status_lo; ue_status_lo >>= 1, i++) { - if (ue_status_lo & 1) + if (ue_lo) { + for (i = 0; ue_lo; ue_lo >>= 1, i++) { + if (ue_lo & 1) dev_err(&adapter->pdev->dev, "UE: %s bit set\n", ue_status_low_desc[i]); } } - if (ue_status_hi) { - for (i = 0; ue_status_hi; ue_status_hi >>= 1, i++) { - if (ue_status_hi & 1) + if (ue_hi) { + for (i = 0; ue_hi; ue_hi >>= 1, i++) { + if (ue_hi & 1) dev_err(&adapter->pdev->dev, "UE: %s bit set\n", ue_status_hi_desc[i]); } } + if (sliport_status & SLIPORT_STATUS_ERR_MASK) { + dev_err(&adapter->pdev->dev, + "sliport status 0x%x\n", sliport_status); + dev_err(&adapter->pdev->dev, + "sliport error1 0x%x\n", sliport_err1); + dev_err(&adapter->pdev->dev, + "sliport error2 0x%x\n", sliport_err2); + } } static void be_worker(struct work_struct *work) @@ -2022,7 +2042,7 @@ static void be_worker(struct work_struct *work) struct be_rx_obj *rxo; int i; - if (!adapter->ue_detected && !lancer_chip(adapter)) + if (!adapter->ue_detected) be_detect_dump_ue(adapter); /* when interrupts are not yet enabled, just reap any pending -- cgit v0.10.2