* Re: [PATCH RFC 00/73] tree-wide: clean up some no longer required #include <linux/init.h>
From: Benjamin Herrenschmidt @ 2014-01-28 3:13 UTC (permalink / raw)
To: Paul Gortmaker
Cc: Stephen Rothwell, linux-arch, linux-mips, linux-m68k, rusty,
linux-ia64, kvm, linux-s390, netdev, x86, linux-kernel, torvalds,
gregkh, linux-alpha, sparclinux, akpm, linuxppc-dev,
linux-arm-kernel
In-Reply-To: <20140123003838.GA10182@windriver.com>
On Wed, 2014-01-22 at 19:38 -0500, Paul Gortmaker wrote:
> Thanks, it was a great help as it uncovered a few issues in fringe arch
> that I didn't have toolchains for, and I've fixed all of those up.
>
> I've noticed that powerpc has been un-buildable for a while now; I have
> used this hack patch locally so I could run the ppc defconfigs to check
> that I didn't break anything. Maybe useful for linux-next in the
> interim? It is a hack patch -- Not-Signed-off-by: Paul Gortmaker. :)
Can you and/or Aneesh submit that as a proper patch (with S-O-B
etc...) ?
Thanks !
Cheers,
Ben.
> Paul.
> --
>
> diff --git a/arch/powerpc/include/asm/pgtable-ppc64.h b/arch/powerpc/include/asm/pgtable-ppc64.h
> index d27960c89a71..d0f070a2b395 100644
> --- a/arch/powerpc/include/asm/pgtable-ppc64.h
> +++ b/arch/powerpc/include/asm/pgtable-ppc64.h
> @@ -560,9 +560,9 @@ extern void pmdp_invalidate(struct vm_area_struct *vma, unsigned long address,
> pmd_t *pmdp);
>
> #define pmd_move_must_withdraw pmd_move_must_withdraw
> -typedef struct spinlock spinlock_t;
> -static inline int pmd_move_must_withdraw(spinlock_t *new_pmd_ptl,
> - spinlock_t *old_pmd_ptl)
> +struct spinlock;
> +static inline int pmd_move_must_withdraw(struct spinlock *new_pmd_ptl,
> + struct spinlock *old_pmd_ptl)
> {
> /*
> * Archs like ppc64 use pgtable to store per pmd
>
> _______________________________________________
> Linuxppc-dev mailing list
> Linuxppc-dev@lists.ozlabs.org
> https://lists.ozlabs.org/listinfo/linuxppc-dev
^ permalink raw reply
* Re: [Xen-devel] [PATCH net-next v5] xen-netfront: clean up code in xennet_release_rx_bufs
From: annie li @ 2014-01-28 3:29 UTC (permalink / raw)
To: David Miller; +Cc: david.vrabel, wei.liu2, ian.campbell, netdev, xen-devel
In-Reply-To: <20140127.130921.7056971883805642.davem@davemloft.net>
On 2014/1/28 5:09, David Miller wrote:
> From: David Vrabel <david.vrabel@citrix.com>
> Date: Mon, 27 Jan 2014 10:22:58 +0000
>
>> I think this should be applied to net (and tagged as a stable candidate)
>> rather than net-next as this fixes are very big resource leak.
> Then this subject line and commit message must be fixed to make it clear
> that this is a BUG fix, rather then just a "clean up".
>
I will post a new patch with correct subject and commit message.
Thanks
Annie
^ permalink raw reply
* [Xen-devel] [PATCH net v6] xen-netfront: fix resource leak in netfront
From: Annie Li @ 2014-01-28 3:35 UTC (permalink / raw)
To: xen-devel, netdev
Cc: konrad.wilk, ian.campbell, wei.liu2, david.vrabel, annie.li
From: Annie Li <annie.li@oracle.com>
This patch removes grant transfer releasing code from netfront, and uses
gnttab_end_foreign_access to end grant access since
gnttab_end_foreign_access_ref may fail when the grant entry is
currently used for reading or writing.
* clean up grant transfer code kept from old netfront(2.6.18) which grants
pages for access/map and transfer. But grant transfer is deprecated in current
netfront, so remove corresponding release code for transfer.
* fix resource leak, release grant access (through gnttab_end_foreign_access)
and skb for tx/rx path, use get_page to ensure page is released when grant
access is completed successfully.
Xen-blkfront/xen-tpmfront/xen-pcifront also have similar issue, but patches
for them will be created separately.
V6: Correct subject line and commit message.
V5: Remove unecessary change in xennet_end_access.
V4: Revert put_page in gnttab_end_foreign_access, and keep netfront change in
single patch.
V3: Changes as suggestion from David Vrabel, ensure pages are not freed untill
grant acess is ended.
V2: Improve patch comments.
Signed-off-by: Annie Li <annie.li@oracle.com>
---
drivers/net/xen-netfront.c | 88 +++++++++++++-------------------------------
1 files changed, 26 insertions(+), 62 deletions(-)
diff --git a/drivers/net/xen-netfront.c b/drivers/net/xen-netfront.c
index d7bee8a..6ddf1e6 100644
--- a/drivers/net/xen-netfront.c
+++ b/drivers/net/xen-netfront.c
@@ -117,6 +117,7 @@ struct netfront_info {
} tx_skbs[NET_TX_RING_SIZE];
grant_ref_t gref_tx_head;
grant_ref_t grant_tx_ref[NET_TX_RING_SIZE];
+ struct page *grant_tx_page[NET_TX_RING_SIZE];
unsigned tx_skb_freelist;
spinlock_t rx_lock ____cacheline_aligned_in_smp;
@@ -396,6 +397,7 @@ static void xennet_tx_buf_gc(struct net_device *dev)
gnttab_release_grant_reference(
&np->gref_tx_head, np->grant_tx_ref[id]);
np->grant_tx_ref[id] = GRANT_INVALID_REF;
+ np->grant_tx_page[id] = NULL;
add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, id);
dev_kfree_skb_irq(skb);
}
@@ -452,6 +454,7 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
gnttab_grant_foreign_access_ref(ref, np->xbdev->otherend_id,
mfn, GNTMAP_readonly);
+ np->grant_tx_page[id] = virt_to_page(data);
tx->gref = np->grant_tx_ref[id] = ref;
tx->offset = offset;
tx->size = len;
@@ -497,6 +500,7 @@ static void xennet_make_frags(struct sk_buff *skb, struct net_device *dev,
np->xbdev->otherend_id,
mfn, GNTMAP_readonly);
+ np->grant_tx_page[id] = page;
tx->gref = np->grant_tx_ref[id] = ref;
tx->offset = offset;
tx->size = bytes;
@@ -596,6 +600,7 @@ static int xennet_start_xmit(struct sk_buff *skb, struct net_device *dev)
mfn = virt_to_mfn(data);
gnttab_grant_foreign_access_ref(
ref, np->xbdev->otherend_id, mfn, GNTMAP_readonly);
+ np->grant_tx_page[id] = virt_to_page(data);
tx->gref = np->grant_tx_ref[id] = ref;
tx->offset = offset;
tx->size = len;
@@ -1085,10 +1090,11 @@ static void xennet_release_tx_bufs(struct netfront_info *np)
continue;
skb = np->tx_skbs[i].skb;
- gnttab_end_foreign_access_ref(np->grant_tx_ref[i],
- GNTMAP_readonly);
- gnttab_release_grant_reference(&np->gref_tx_head,
- np->grant_tx_ref[i]);
+ get_page(np->grant_tx_page[i]);
+ gnttab_end_foreign_access(np->grant_tx_ref[i],
+ GNTMAP_readonly,
+ (unsigned long)page_address(np->grant_tx_page[i]));
+ np->grant_tx_page[i] = NULL;
np->grant_tx_ref[i] = GRANT_INVALID_REF;
add_id_to_freelist(&np->tx_skb_freelist, np->tx_skbs, i);
dev_kfree_skb_irq(skb);
@@ -1097,78 +1103,35 @@ static void xennet_release_tx_bufs(struct netfront_info *np)
static void xennet_release_rx_bufs(struct netfront_info *np)
{
- struct mmu_update *mmu = np->rx_mmu;
- struct multicall_entry *mcl = np->rx_mcl;
- struct sk_buff_head free_list;
- struct sk_buff *skb;
- unsigned long mfn;
- int xfer = 0, noxfer = 0, unused = 0;
int id, ref;
- dev_warn(&np->netdev->dev, "%s: fix me for copying receiver.\n",
- __func__);
- return;
-
- skb_queue_head_init(&free_list);
-
spin_lock_bh(&np->rx_lock);
for (id = 0; id < NET_RX_RING_SIZE; id++) {
- ref = np->grant_rx_ref[id];
- if (ref == GRANT_INVALID_REF) {
- unused++;
- continue;
- }
+ struct sk_buff *skb;
+ struct page *page;
skb = np->rx_skbs[id];
- mfn = gnttab_end_foreign_transfer_ref(ref);
- gnttab_release_grant_reference(&np->gref_rx_head, ref);
- np->grant_rx_ref[id] = GRANT_INVALID_REF;
-
- if (0 == mfn) {
- skb_shinfo(skb)->nr_frags = 0;
- dev_kfree_skb(skb);
- noxfer++;
+ if (!skb)
continue;
- }
- if (!xen_feature(XENFEAT_auto_translated_physmap)) {
- /* Remap the page. */
- const struct page *page =
- skb_frag_page(&skb_shinfo(skb)->frags[0]);
- unsigned long pfn = page_to_pfn(page);
- void *vaddr = page_address(page);
+ ref = np->grant_rx_ref[id];
+ if (ref == GRANT_INVALID_REF)
+ continue;
- MULTI_update_va_mapping(mcl, (unsigned long)vaddr,
- mfn_pte(mfn, PAGE_KERNEL),
- 0);
- mcl++;
- mmu->ptr = ((u64)mfn << PAGE_SHIFT)
- | MMU_MACHPHYS_UPDATE;
- mmu->val = pfn;
- mmu++;
+ page = skb_frag_page(&skb_shinfo(skb)->frags[0]);
- set_phys_to_machine(pfn, mfn);
- }
- __skb_queue_tail(&free_list, skb);
- xfer++;
- }
-
- dev_info(&np->netdev->dev, "%s: %d xfer, %d noxfer, %d unused\n",
- __func__, xfer, noxfer, unused);
+ /* gnttab_end_foreign_access() needs a page ref until
+ * foreign access is ended (which may be deferred).
+ */
+ get_page(page);
+ gnttab_end_foreign_access(ref, 0,
+ (unsigned long)page_address(page));
+ np->grant_rx_ref[id] = GRANT_INVALID_REF;
- if (xfer) {
- if (!xen_feature(XENFEAT_auto_translated_physmap)) {
- /* Do all the remapping work and M2P updates. */
- MULTI_mmu_update(mcl, np->rx_mmu, mmu - np->rx_mmu,
- NULL, DOMID_SELF);
- mcl++;
- HYPERVISOR_multicall(np->rx_mcl, mcl - np->rx_mcl);
- }
+ kfree_skb(skb);
}
- __skb_queue_purge(&free_list);
-
spin_unlock_bh(&np->rx_lock);
}
@@ -1339,6 +1302,7 @@ static struct net_device *xennet_create_dev(struct xenbus_device *dev)
for (i = 0; i < NET_RX_RING_SIZE; i++) {
np->rx_skbs[i] = NULL;
np->grant_rx_ref[i] = GRANT_INVALID_REF;
+ np->grant_tx_page[i] = NULL;
}
/* A grant for every tx ring slot */
--
1.7.3.4
^ permalink raw reply related
* Re: [Xen-devel] [PATCH net v6] xen-netfront: fix resource leak in netfront
From: David Miller @ 2014-01-28 3:49 UTC (permalink / raw)
To: Annie.li
Cc: xen-devel, netdev, konrad.wilk, ian.campbell, wei.liu2,
david.vrabel
In-Reply-To: <1390880142-4962-1-git-send-email-Annie.li@oracle.com>
From: Annie Li <Annie.li@oracle.com>
Date: Tue, 28 Jan 2014 11:35:42 +0800
> This patch removes grant transfer releasing code from netfront, and uses
> gnttab_end_foreign_access to end grant access since
> gnttab_end_foreign_access_ref may fail when the grant entry is
> currently used for reading or writing.
Applied and queued up for -stable, thanks.
^ permalink raw reply
* [PATCH net-next] bonding: fix locking in bond_loadbalance_arp_mon()
From: Ding Tianhong @ 2014-01-28 3:48 UTC (permalink / raw)
To: Jay Vosburgh, Veaceslav Falico, David S. Miller, Netdev,
Andy Gospodarek
The commit 1d3ee88ae0d605629bf369
(bonding: add netlink attributes to slave link dev)
has add rtmsg_ifinfo() in bond_set_active_slave() and
bond_set_backup_slave(), so the two function need to
called in RTNL lock, but bond_loadbalance_arp_mon()
only calling these functions in RCU, warning message
will occurs.
fix this by add a new function bond_slave_state_change(),
which will reset the slave's state after slave link check,
so remove the bond_set_xxx_slave() from the cycle and only
record the slave_state_changed, this will call the new
function to set all slaves to new state in RTNL later.
Cc: Jay Vosburgh <fubar@us.ibm.com>
Cc: Veaceslav Falico <vfalico@redhat.com>
Cc: Andy Gospodarek <andy@greyhouse.net>
Signed-off-by: Ding Tianhong <dingtianhong@huawei.com>
---
drivers/net/bonding/bond_main.c | 29 +++++++++++++++++------------
drivers/net/bonding/bonding.h | 13 +++++++++++++
2 files changed, 30 insertions(+), 12 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index f9e0c8b..dd2dcc6 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -2346,7 +2346,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
arp_work.work);
struct slave *slave, *oldcurrent;
struct list_head *iter;
- int do_failover = 0;
+ int do_failover = 0, slave_state_changed = 0;
if (!bond_has_slaves(bond))
goto re_arm;
@@ -2370,7 +2370,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
bond_time_in_interval(bond, slave->dev->last_rx, 1)) {
slave->link = BOND_LINK_UP;
- bond_set_active_slave(slave);
+ slave_state_changed = 1;
/* primary_slave has no meaning in round-robin
* mode. the window of a slave being up and
@@ -2399,7 +2399,7 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
!bond_time_in_interval(bond, slave->dev->last_rx, 2)) {
slave->link = BOND_LINK_DOWN;
- bond_set_backup_slave(slave);
+ slave_state_changed = 1;
if (slave->link_failure_count < UINT_MAX)
slave->link_failure_count++;
@@ -2426,19 +2426,24 @@ static void bond_loadbalance_arp_mon(struct work_struct *work)
rcu_read_unlock();
- if (do_failover) {
- /* the bond_select_active_slave must hold RTNL
- * and curr_slave_lock for write.
- */
+ if (do_failover || slave_state_changed) {
if (!rtnl_trylock())
goto re_arm;
- block_netpoll_tx();
- write_lock_bh(&bond->curr_slave_lock);
- bond_select_active_slave(bond);
+ if (slave_state_changed) {
+ bond_slave_state_change(bond);
+ } else if (do_failover) {
+ /* the bond_select_active_slave must hold RTNL
+ * and curr_slave_lock for write.
+ */
+ block_netpoll_tx();
+ write_lock_bh(&bond->curr_slave_lock);
- write_unlock_bh(&bond->curr_slave_lock);
- unblock_netpoll_tx();
+ bond_select_active_slave(bond);
+
+ write_unlock_bh(&bond->curr_slave_lock);
+ unblock_netpoll_tx();
+ }
rtnl_unlock();
}
diff --git a/drivers/net/bonding/bonding.h b/drivers/net/bonding/bonding.h
index 1a9062f..86ccfb9 100644
--- a/drivers/net/bonding/bonding.h
+++ b/drivers/net/bonding/bonding.h
@@ -303,6 +303,19 @@ static inline void bond_set_backup_slave(struct slave *slave)
}
}
+static inline void bond_slave_state_change(struct bonding *bond)
+{
+ struct list_head *iter;
+ struct slave *tmp;
+
+ bond_for_each_slave(bond, tmp, iter) {
+ if (tmp->link == BOND_LINK_UP)
+ bond_set_active_slave(tmp);
+ else if (tmp->link == BOND_LINK_DOWN)
+ bond_set_backup_slave(tmp);
+ }
+}
+
static inline int bond_slave_state(struct slave *slave)
{
return slave->backup;
--
1.8.0
^ permalink raw reply related
* [PATCH v2] net: gre: use icmp_hdr() to get inner ip header
From: Duan Jiong @ 2014-01-28 3:49 UTC (permalink / raw)
To: David Miller; +Cc: Daniel Borkmann, netdev, Pravin Shelar
When dealing with icmp messages, the skb->data points the
ip header that triggered the sending of the icmp message.
In gre_cisco_err(), the parse_gre_header() is called, and the
iptunnel_pull_header() is called to pull the skb at the end of
the parse_gre_header(), so the skb->data doesn't point the
inner ip header.
Unfortunately, the ipgre_err still needs those ip addresses in
inner ip header to look up tunnel by ip_tunnel_lookup().
So just use icmp_hdr() to get inner ip header instead of skb->data.
Signed-off-by: Duan Jiong <duanj.fnst@cn.fujitsu.com>
---
v2: use icmp_hdr() instead of conditional pulling of headers
net/ipv4/ip_gre.c | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
index e7a92fd..ec4f762 100644
--- a/net/ipv4/ip_gre.c
+++ b/net/ipv4/ip_gre.c
@@ -178,7 +178,7 @@ static int ipgre_err(struct sk_buff *skb, u32 info,
else
itn = net_generic(net, ipgre_net_id);
- iph = (const struct iphdr *)skb->data;
+ iph = (const struct iphdr *)(icmp_hdr(skb) + 1);
t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
iph->daddr, iph->saddr, tpi->key);
--
1.8.3.1
^ permalink raw reply related
* i40e: Add missing braces to i40e_dcb_need_reconfig()
From: Dave Jones @ 2014-01-28 4:11 UTC (permalink / raw)
To: netdev; +Cc: Neerav.Parikh
Indentation mismatch spotted with Coverity.
Introduced in 4e3b35b044ea ("i40e: add DCB and DCBNL support")
Signed-off-by: Dave Jones <davej@fedoraproject.org>
diff --git a/drivers/net/ethernet/intel/i40e/i40e_main.c b/drivers/net/ethernet/intel/i40e/i40e_main.c
index a4b940862b83..b901371ca361 100644
--- a/drivers/net/ethernet/intel/i40e/i40e_main.c
+++ b/drivers/net/ethernet/intel/i40e/i40e_main.c
@@ -4440,9 +4440,10 @@ bool i40e_dcb_need_reconfig(struct i40e_pf *pf,
/* Check if APP Table has changed */
if (memcmp(&new_cfg->app,
&old_cfg->app,
- sizeof(new_cfg->app)))
+ sizeof(new_cfg->app))) {
need_reconfig = true;
dev_info(&pf->pdev->dev, "APP Table change detected.\n");
+ }
return need_reconfig;
}
^ permalink raw reply related
* Re: i40e: Add missing braces to i40e_dcb_need_reconfig()
From: David Miller @ 2014-01-28 4:17 UTC (permalink / raw)
To: davej; +Cc: netdev, Neerav.Parikh
In-Reply-To: <20140128041109.GA25771@redhat.com>
From: Dave Jones <davej@redhat.com>
Date: Mon, 27 Jan 2014 23:11:09 -0500
> Indentation mismatch spotted with Coverity.
> Introduced in 4e3b35b044ea ("i40e: add DCB and DCBNL support")
>
> Signed-off-by: Dave Jones <davej@fedoraproject.org>
Looks straightforward enough for me to apply directly, thanks
Dave.
^ permalink raw reply
* [PATCH] net: Document promote_secondaries
From: Martin Schwenke @ 2014-01-28 4:26 UTC (permalink / raw)
To: netdev; +Cc: David S. Miller
>From 038a821667f62c496f2bbae27081b1b612122a97 Mon Sep 17 00:00:00 2001
From: Martin Schwenke <martin@meltin.net>
Date: Tue, 28 Jan 2014 15:16:49 +1100
Subject: [PATCH] net: Document promote_secondaries
This option was added a long time ago...
commit 8f937c6099858eee15fae14009dcbd05177fa91d
Author: Harald Welte <laforge@gnumonks.org>
Date: Sun May 29 20:23:46 2005 -0700
[IPV4]: Primary and secondary addresses
Signed-off-by: Martin Schwenke <martin@meltin.net>
---
Documentation/networking/ip-sysctl.txt | 6 ++++++
1 file changed, 6 insertions(+)
diff --git a/Documentation/networking/ip-sysctl.txt b/Documentation/networking/ip-sysctl.txt
index 5de0374..ab42c95 100644
--- a/Documentation/networking/ip-sysctl.txt
+++ b/Documentation/networking/ip-sysctl.txt
@@ -1088,6 +1088,12 @@ igmpv3_unsolicited_report_interval - INTEGER
IGMPv3 report retransmit will take place.
Default: 1000 (1 seconds)
+promote_secondaries - BOOLEAN
+ When a primary IP address is removed from this interface
+ promote a corresponding secondary IP address instead of
+ removing all the corresponding secondary IP addresses.
+
+
tag - INTEGER
Allows you to write a number, which can be used as required.
Default value is 0.
--
1.8.5.3
^ permalink raw reply related
* Re: [PATCH v2] net: gre: use icmp_hdr() to get inner ip header
From: David Miller @ 2014-01-28 4:39 UTC (permalink / raw)
To: duanj.fnst; +Cc: dborkman, netdev, pshelar
In-Reply-To: <52E728D7.70506@cn.fujitsu.com>
From: Duan Jiong <duanj.fnst@cn.fujitsu.com>
Date: Tue, 28 Jan 2014 11:49:43 +0800
>
> When dealing with icmp messages, the skb->data points the
> ip header that triggered the sending of the icmp message.
>
> In gre_cisco_err(), the parse_gre_header() is called, and the
> iptunnel_pull_header() is called to pull the skb at the end of
> the parse_gre_header(), so the skb->data doesn't point the
> inner ip header.
>
> Unfortunately, the ipgre_err still needs those ip addresses in
> inner ip header to look up tunnel by ip_tunnel_lookup().
>
> So just use icmp_hdr() to get inner ip header instead of skb->data.
>
> Signed-off-by: Duan Jiong <duanj.fnst@cn.fujitsu.com>
Applied and queued up for -stable, thanks.
^ permalink raw reply
* Re: [PATCH] net: Document promote_secondaries
From: David Miller @ 2014-01-28 4:39 UTC (permalink / raw)
To: martin; +Cc: netdev
In-Reply-To: <20140128152642.20d94df3@martins.ozlabs.org>
From: Martin Schwenke <martin@meltin.net>
Date: Tue, 28 Jan 2014 15:26:42 +1100
> From 038a821667f62c496f2bbae27081b1b612122a97 Mon Sep 17 00:00:00 2001
> From: Martin Schwenke <martin@meltin.net>
> Date: Tue, 28 Jan 2014 15:16:49 +1100
> Subject: [PATCH] net: Document promote_secondaries
>
> This option was added a long time ago...
>
> commit 8f937c6099858eee15fae14009dcbd05177fa91d
> Author: Harald Welte <laforge@gnumonks.org>
> Date: Sun May 29 20:23:46 2005 -0700
>
> [IPV4]: Primary and secondary addresses
>
> Signed-off-by: Martin Schwenke <martin@meltin.net>
Applied, thanks.
^ permalink raw reply
* Re: [Patch net-next v2 1/5] net_sched: act: hide struct tcf_common from API
From: Cong Wang @ 2014-01-28 5:17 UTC (permalink / raw)
To: Jamal Hadi Salim; +Cc: Linux Kernel Network Developers, David S. Miller
In-Reply-To: <52E64D03.7000506@mojatatu.com>
On Mon, Jan 27, 2014 at 4:11 AM, Jamal Hadi Salim <jhs@mojatatu.com> wrote:
> On 01/23/14 17:35, Cong Wang wrote:
>>
>> Now we can totally hide it from modules. tcf_hash_*() API's
>> will operate on struct tc_action, modules don't need to care about
>> the details.
>>
>> Cc: Jamal Hadi Salim <jhs@mojatatu.com>
>> Cc: David S. Miller <davem@davemloft.net>
>> Signed-off-by: Cong Wang <xiyou.wangcong@gmail.com>
>> ---
>
>
> Cong, this patch does not compile by itself. I did not try the rest.
> For git bisect to work:
> Every patch should be compilable standalone and all tests should
> pass with every single patch (the later part is my view, the first
> is common practise)
I knew, and I thought I did compile-test for every patch, seems
I missed something during update, or you use a different config
to trigger the compile error.
>
> Since Dave already closed the door - no rush, when you get the
> cycles please fix this up. I am hoping to do a quick test run
> when you are done.
>
Yeah, I asked Dave in another thread and decided to wait
for the next net-next.
Thanks.
^ permalink raw reply
* Re: [PATCH v2] net: gre: use icmp_hdr() to get inner ip header
From: Pravin Shelar @ 2014-01-28 5:35 UTC (permalink / raw)
To: Duan Jiong; +Cc: David Miller, Daniel Borkmann, netdev
In-Reply-To: <52E728D7.70506@cn.fujitsu.com>
On Mon, Jan 27, 2014 at 7:49 PM, Duan Jiong <duanj.fnst@cn.fujitsu.com> wrote:
>
> When dealing with icmp messages, the skb->data points the
> ip header that triggered the sending of the icmp message.
>
> In gre_cisco_err(), the parse_gre_header() is called, and the
> iptunnel_pull_header() is called to pull the skb at the end of
> the parse_gre_header(), so the skb->data doesn't point the
> inner ip header.
>
> Unfortunately, the ipgre_err still needs those ip addresses in
> inner ip header to look up tunnel by ip_tunnel_lookup().
>
> So just use icmp_hdr() to get inner ip header instead of skb->data.
>
> Signed-off-by: Duan Jiong <duanj.fnst@cn.fujitsu.com>
> ---
>
> v2: use icmp_hdr() instead of conditional pulling of headers
>
> net/ipv4/ip_gre.c | 2 +-
> 1 file changed, 1 insertion(+), 1 deletion(-)
>
> diff --git a/net/ipv4/ip_gre.c b/net/ipv4/ip_gre.c
> index e7a92fd..ec4f762 100644
> --- a/net/ipv4/ip_gre.c
> +++ b/net/ipv4/ip_gre.c
> @@ -178,7 +178,7 @@ static int ipgre_err(struct sk_buff *skb, u32 info,
> else
> itn = net_generic(net, ipgre_net_id);
>
> - iph = (const struct iphdr *)skb->data;
> + iph = (const struct iphdr *)(icmp_hdr(skb) + 1);
> t = ip_tunnel_lookup(itn, skb->dev->ifindex, tpi->flags,
> iph->daddr, iph->saddr, tpi->key);
>
Don't we need to pull inner ip header first?
> --
> 1.8.3.1
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH] iproute: Fix Netid value for multi-families output
From: Pavel Emelyanov @ 2014-01-28 6:24 UTC (permalink / raw)
To: Stephen Hemminger, Linux Netdev List; +Cc: François-Xavier Le Bail
When requesting simultaneous output of TCP and UDP sockets
the netid field shows "tcp" always.
[root@xemvm1 iproute2]# ./misc/ss -a -tu
Netid State Recv-Q Send-Q Local Address:Port Peer Address:Port
tcp UNCONN 0 0 *:32713 *:*
tcp UNCONN 0 0 *:bootpc *:*
tcp UNCONN 0 0 :::57879 :::*
tcp LISTEN 0 128 *:ssh *:*
tcp ESTAB 0 48 1.2.3.5:ssh 1.2.3.4:45826
tcp ESTAB 0 0 1.2.3.5:ssh 1.2.3.4:45814
tcp LISTEN 0 128 :::ssh :::*
While the 1st 3 sockets are UDP ones:
[root@xemvm1 iproute2]# ./misc/ss -a -u
State Recv-Q Send-Q Local Address:Port Peer Address:Port
UNCONN 0 0 *:32713 *:*
UNCONN 0 0 *:bootpc *:*
UNCONN 0 0 :::57879 :::*
Reported-by: François-Xavier Le Bail <fx.lebail@yahoo.com>
Signed-off-by: Pavel Emelyanov <xemul@parallels.com>
---
diff --git a/misc/ss.c b/misc/ss.c
index 764ffe2..37dcc11 100644
--- a/misc/ss.c
+++ b/misc/ss.c
@@ -1462,7 +1462,21 @@ static void tcp_show_info(const struct nlmsghdr *nlh, struct inet_diag_msg *r,
}
}
-static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f)
+static char *proto_name(int protocol)
+{
+ switch (protocol) {
+ case IPPROTO_UDP:
+ return "udp";
+ case IPPROTO_TCP:
+ return "tcp";
+ case IPPROTO_DCCP:
+ return "dccp";
+ }
+
+ return "???";
+}
+
+static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f, int protocol)
{
struct rtattr * tb[INET_DIAG_MAX+1];
struct inet_diag_msg *r = NLMSG_DATA(nlh);
@@ -1487,7 +1501,7 @@ static int inet_show_sock(struct nlmsghdr *nlh, struct filter *f)
return 0;
if (netid_width)
- printf("%-*s ", netid_width, "tcp");
+ printf("%-*s ", netid_width, proto_name(protocol));
if (state_width)
printf("%-*s ", state_width, sstate_name[s.state]);
@@ -1760,7 +1774,7 @@ again:
h = NLMSG_NEXT(h, status);
continue;
}
- err = inet_show_sock(h, NULL);
+ err = inet_show_sock(h, NULL, protocol);
if (err < 0) {
close(fd);
return err;
@@ -1839,7 +1853,7 @@ static int tcp_show_netlink_file(struct filter *f)
return -1;
}
- err = inet_show_sock(h, f);
+ err = inet_show_sock(h, f, IPPROTO_TCP);
if (err < 0)
return err;
}
^ permalink raw reply related
* Re: How to identify 6to4 and 6in4 tunnels
From: zhuyj @ 2014-01-28 7:32 UTC (permalink / raw)
To: nicolas.dichtel, David S. Miller, netdev, kuznet, jmorris,
yoshfuji, kaber, linux-kernel
In-Reply-To: <52E65817.1090904@6wind.com>
On 01/27/2014 08:59 PM, Nicolas Dichtel wrote:
> Le 27/01/2014 11:39, zhuyj a écrit :
>> Hi, Maintainers
>>
>> In our scene, we will create the 6in4/6to4 tunnel firstly and need to
>> check the
>> tunnel type, secondly, we will configure the ip address on it. So,
>> Could we have
>> any way to get the actual tunnel for 6in4 and 6to4 from current linux
>> version?
>>
>> Both 6in4 and 6to4 have the same protocol “IPPROTO_IPV6” in Linux
>> kernel. The
>> only difference is the ip address on the tunnel. Can we distinguish
>> them in
>> Linux kernel?
> Just check the prefix, like it is done in check_6rd().
>
>
> Regards,
> Nicolas
>
Hi, Nicolas
Thanks for your reply. Maybe I can configure 6to4 tunnel by the
following commands:
ip tunnel add tun6to4 mode sit remote any local 1.202.252.122 ttl 64
ip link set dev tun6to4 up
ip -6 addr add 2002:01ca:fc7a::0012:0225:2122/128 dev tun6to4
ip -6 route add 2000::/3 via ::192.88.99.1 dev tun6to4 metric 1
But the kernel can not identify the tunnel is 6to4 tunnel or 6in4 tunnel
immediately. After the packets travel through this tunnel, the kernel
can identify the type of the tunnel by check_6rd.
Is it right?
Best Regards!
Zhu Yanjun
^ permalink raw reply
* Re: How to identify 6to4 and 6in4 tunnels
From: zhuyj @ 2014-01-28 7:39 UTC (permalink / raw)
To: nicolas.dichtel, David S. Miller, netdev, kuznet, jmorris,
yoshfuji, kaber, linux-kernel, zhuyj
In-Reply-To: <52E75D23.10909@gmail.com>
On 01/28/2014 03:32 PM, zhuyj wrote:
> On 01/27/2014 08:59 PM, Nicolas Dichtel wrote:
>> Le 27/01/2014 11:39, zhuyj a écrit :
>>> Hi, Maintainers
>>>
>>> In our scene, we will create the 6in4/6to4 tunnel firstly and need
>>> to check the
>>> tunnel type, secondly, we will configure the ip address on it. So,
>>> Could we have
>>> any way to get the actual tunnel for 6in4 and 6to4 from current
>>> linux version?
>>>
>>> Both 6in4 and 6to4 have the same protocol “IPPROTO_IPV6” in Linux
>>> kernel. The
>>> only difference is the ip address on the tunnel. Can we distinguish
>>> them in
>>> Linux kernel?
>> Just check the prefix, like it is done in check_6rd().
>>
>>
>> Regards,
>> Nicolas
Hi, Nicolas
Thanks for your reply. Maybe I can configure 6to4 tunnel by the
following commands:
ip tunnel add tun6to4 mode sit remote any local 1.202.252.122 ttl 64
ip link set dev tun6to4 up
ip -6 addr add 2002:01ca:fc7a::0012:0225:2122/128 dev tun6to4
ip -6 route add 2000::/3 via ::192.88.99.1 dev tun6to4 metric 1
But the kernel can not identify the tunnel is 6to4 tunnel or 6in4 tunnel
immediately. After the packets travel through this tunnel, the kernel
can identify the type of the tunnel by check_6rd.
Is it right?
Best Regards!
Zhu Yanjun
^ permalink raw reply
* Re: [RFC ipsec-next] xfrm: avoid creating temporary SA when there are no listeners
From: Steffen Klassert @ 2014-01-28 7:59 UTC (permalink / raw)
To: Horia Geanta; +Cc: David S. Miller, netdev
In-Reply-To: <1390729852-7842-2-git-send-email-horia.geanta@freescale.com>
On Sun, Jan 26, 2014 at 11:50:52AM +0200, Horia Geanta wrote:
> In the case when KMs have no listeners, km_query() will fail and
> temporary SAs are garbage collected immediately after their allocation.
> This causes strain on memory allocation, leading even to OOM since
> temporary SA alloc/free cycle is performed for every packet
> and garbage collection does not keep up the pace.
>
> The sane thing to do is to make sure we have audience before
> temporary SA allocation.
>
> Signed-off-by: Horia Geanta <horia.geanta@freescale.com>
No objections from me, looks ok.
^ permalink raw reply
* Re: [PATCH 0/2] sctp: fix a problem with net_namespace
From: Wang Weidong @ 2014-01-28 8:13 UTC (permalink / raw)
To: Neil Horman; +Cc: davem, vyasevich, dborkman, netdev
In-Reply-To: <20140127114904.GA17143@hmsreliant.think-freely.org>
On 2014/1/27 19:49, Neil Horman wrote:
> On Mon, Jan 27, 2014 at 11:49:01AM +0800, Wang Weidong wrote:
>> fix a problem with net_namespace, and optimize
>> the sctp_sysctl_net_register.
>>
>> Wang Weidong (2):
>> sctp: fix a missed .data initialization
>> sctp: optimize the sctp_sysctl_net_register
>>
>> net/sctp/sysctl.c | 17 ++++++++++-------
>> 1 file changed, 10 insertions(+), 7 deletions(-)
>>
>> --
>> 1.7.12
>>
>>
>>
> I don't see that either of these patches are needed. In sctp_init_net, the
> sctp_hmac_alg pointer gets initalized before calling sctp_sysctl_net_register,
> and sctp_proc_do_hmac_alg is written to specifically expect NULL values, so this
> code may change behavior regarding default cookie selection.
>
Hi Neil,
Here, I think the sctp_proc_do_hmac_alg will be called only when we change the
/proc/sys/net/cookie_hmac_alg. So add the .data won't effect the default value.
and the data isn't equal to the "cookie_hmac_alg"?
> This was coded so that poniters to entires in the string table could be used,
> rather than needing to allocate or maintain character buffers. That said, it
> does look like that for loop in sctp_sysctl_register_table might compute an odd
> offset when cloning the table. I think the right fix for that is likely to just
> move the sysctl value initalization in sctp_init_net to below the sysctl
> register function.
>
> Neil
>
I found the problem is that:
I use "ip netns add netns1/netns2"
In any netns(netns1 or netns2 or init_net) when I change the value of the entry
such as "addip_enable" "max_autoclose" which after the cookie_hmac_alg (contain it),
and the other netns will be effected.
In sctp_sysctl_net_register, kmemdup does cloning the table. The offset of netns1 and
init_net's clt_table.data is the same as two netns offset. So the for(){...} would do
add the offset for every clt_table.data.
The code:
for (i = 0; table[i].data; i++)
table[i].data += (char *)(&net->sctp) - (char *)&init_net.sctp;
And I add a pr_info into the for(){...} in sctp_sysctl_net_register and only print 7 times for each ns.
7 is the index of "cookie_preserve_enable" which before the "cookie_hmac_alg".
As the "cookie_hmac_alg" data is NULL, so we can't add offset to the rest, and all the netns use the same
address of clt_table entry after the "cookie_hmac_alg".
So I think only "move the sysctl value initalization in sctp_init_net to below the sysctl
register function" won't solve the problem, because the problem is at the for() {...}.
Is there something wrong?
The next patch is that, the sctp_net_table is for init_net, So when load the sctp module, we needn't
to do the cloning tables for init_net again. And I found the ipv4 do it in the same way.
I have a doubt : how can I rmmod the sctp? only add '-f' ? If I do "rmmod -f sctp", I will get the
log by dmesg: "Disabling lock debugging due to kernel taint"
Regards,
Wang
>
>
^ permalink raw reply
* 8% performance improved by change tap interact with kernel stack
From: Qin Chuanyu @ 2014-01-28 8:14 UTC (permalink / raw)
To: jasowang, Michael S. Tsirkin, Anthony Liguori, KVM list, netdev
according perf test result,I found that there are 5%-8% cpu cost on
softirq by use netif_rx_ni called in tun_get_user.
so I changed the function which cause skb transmitted more quickly.
from
tun_get_user ->
netif_rx_ni(skb);
to
tun_get_user ->
rcu_read_lock_bh();
netif_receive_skb(skb);
rcu_read_unlock_bh();
The test result is as below:
CPU: Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
NIC: intel 82599
Host OS/Guest OS:suse11sp3
Qemu-1.6
netperf udp 512(VM tx)
test model: VM->host->host
modified before : 2.00Gbps 461146pps
modified after : 2.16Gbps 498782pps
8% performance gained from this change,
Is there any problem for this patch ?
^ permalink raw reply
* [PATCH] USB2NET : SR9800 : One chip USB2.0 USB2NET SR9800 Device Driver Support
From: liujunliang_ljl @ 2014-01-28 8:36 UTC (permalink / raw)
To: davem
Cc: horms, joe, romieu, gregkh, netdev, linux-usb, linux-kernel,
sunhecheng, liujunliang_ljl
From: Liu Junliang <liujunliang_ljl@163.com>
Signed-off-by: Liu Junliang <liujunliang_ljl@163.com>
---
drivers/net/usb/Kconfig | 16 +
drivers/net/usb/Makefile | 1 +
drivers/net/usb/sr9800.c | 874 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/usb/sr9800.h | 202 +++++++++++
4 files changed, 1093 insertions(+)
create mode 100644 drivers/net/usb/sr9800.c
create mode 100644 drivers/net/usb/sr9800.h
diff --git a/drivers/net/usb/Kconfig b/drivers/net/usb/Kconfig
index 47b0f73..2551bf6 100644
--- a/drivers/net/usb/Kconfig
+++ b/drivers/net/usb/Kconfig
@@ -291,6 +291,22 @@ config USB_NET_SR9700
This option adds support for CoreChip-sz SR9700 based USB 1.1
10/100 Ethernet adapters.
+config USB_NET_SR9800
+ tristate "CoreChip-sz SR9800 based USB 2.0 10/100 ethernet devices"
+ depends on USB_USBNET
+ select CRC32
+ default y
+ ---help---
+ Say Y if you want to use one of the following 100Mbps USB Ethernet
+ device based on the CoreChip-sz SR9800 chip.
+
+ This driver makes the adapter appear as a normal Ethernet interface,
+ typically on eth0, if it is the only ethernet device, or perhaps on
+ eth1, if you have a PCI or ISA ethernet card installed.
+
+ To compile this driver as a module, choose M here: the
+ module will be called sr9800.
+
config USB_NET_SMSC75XX
tristate "SMSC LAN75XX based USB 2.0 gigabit ethernet devices"
depends on USB_USBNET
diff --git a/drivers/net/usb/Makefile b/drivers/net/usb/Makefile
index b17b5e8..433f0a0 100644
--- a/drivers/net/usb/Makefile
+++ b/drivers/net/usb/Makefile
@@ -15,6 +15,7 @@ obj-$(CONFIG_USB_NET_CDCETHER) += cdc_ether.o r815x.o
obj-$(CONFIG_USB_NET_CDC_EEM) += cdc_eem.o
obj-$(CONFIG_USB_NET_DM9601) += dm9601.o
obj-$(CONFIG_USB_NET_SR9700) += sr9700.o
+obj-$(CONFIG_USB_NET_SR9800) += sr9800.o
obj-$(CONFIG_USB_NET_SMSC75XX) += smsc75xx.o
obj-$(CONFIG_USB_NET_SMSC95XX) += smsc95xx.o
obj-$(CONFIG_USB_NET_GL620A) += gl620a.o
diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c
new file mode 100644
index 0000000..ab15973
--- /dev/null
+++ b/drivers/net/usb/sr9800.c
@@ -0,0 +1,874 @@
+/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices
+ *
+ * Author : Liu Junliang <liujunliang_ljl@163.com>
+ *
+ * Based on asix_common.c, asix_devices.c
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.*
+ */
+
+#include <linux/module.h>
+#include <linux/kmod.h>
+#include <linux/init.h>
+#include <linux/netdevice.h>
+#include <linux/etherdevice.h>
+#include <linux/ethtool.h>
+#include <linux/workqueue.h>
+#include <linux/mii.h>
+#include <linux/usb.h>
+#include <linux/crc32.h>
+#include <linux/usb/usbnet.h>
+#include <linux/slab.h>
+#include <linux/if_vlan.h>
+
+#include "sr9800.h"
+
+static int sr_read_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ int err;
+
+ err = usbnet_read_cmd(dev, cmd, SR_REQ_RD_REG, value, index,
+ data, size);
+ if ((err != size) && (err >= 0))
+ err = -EINVAL;
+
+ return err;
+}
+
+static int sr_write_cmd(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ int err;
+
+ err = usbnet_write_cmd(dev, cmd, SR_REQ_WR_REG, value, index,
+ data, size);
+ if ((err != size) && (err >= 0))
+ err = -EINVAL;
+
+ return err;
+}
+
+static void
+sr_write_cmd_async(struct usbnet *dev, u8 cmd, u16 value, u16 index,
+ u16 size, void *data)
+{
+ usbnet_write_cmd_async(dev, cmd, SR_REQ_WR_REG, value, index, data,
+ size);
+}
+
+static int sr_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
+{
+ int offset = 0;
+
+ while (offset + sizeof(u32) < skb->len) {
+ struct sk_buff *sr_skb;
+ u16 size;
+ u32 header = get_unaligned_le32(skb->data + offset);
+
+ offset += sizeof(u32);
+ /* get the packet length */
+ size = (u16) (header & 0x7ff);
+ if (size != ((~header >> 16) & 0x07ff)) {
+ netdev_err(dev->net,
+ "sr_rx_fixup() Bad Header Length\n");
+ return 0;
+ }
+
+ if ((size > dev->net->mtu + ETH_HLEN + VLAN_HLEN) ||
+ (size + offset > skb->len)) {
+ netdev_err(dev->net,
+ "sr_rx_fixup() Bad RX Length %d\n", size);
+ return 0;
+ }
+ sr_skb = netdev_alloc_skb_ip_align(dev->net, size);
+ if (!sr_skb)
+ return 0;
+
+ skb_put(sr_skb, size);
+ memcpy(sr_skb->data, skb->data + offset, size);
+ usbnet_skb_return(dev, sr_skb);
+
+ offset += (size + 1) & 0xfffe;
+ }
+
+ if (skb->len != offset) {
+ netdev_err(dev->net, "sr_rx_fixup() Bad SKB Length %d\n",
+ skb->len);
+ return 0;
+ }
+
+ return 1;
+}
+
+static struct sk_buff *sr_tx_fixup(struct usbnet *dev, struct sk_buff *skb,
+ gfp_t flags)
+{
+ int headroom = skb_headroom(skb);
+ int tailroom = skb_tailroom(skb);
+ u32 padbytes = 0xffff0000;
+ u32 packet_len;
+ int padlen;
+
+ padlen = ((skb->len + 4) % (dev->maxpacket - 1)) ? 0 : 4;
+
+ if ((!skb_cloned(skb)) && ((headroom + tailroom) >= (4 + padlen))) {
+ if ((headroom < 4) || (tailroom < padlen)) {
+ skb->data = memmove(skb->head + 4, skb->data,
+ skb->len);
+ skb_set_tail_pointer(skb, skb->len);
+ }
+ } else {
+ struct sk_buff *skb2;
+ skb2 = skb_copy_expand(skb, 4, padlen, flags);
+ dev_kfree_skb_any(skb);
+ skb = skb2;
+ if (!skb)
+ return NULL;
+ }
+
+ skb_push(skb, 4);
+ packet_len = (((skb->len - 4) ^ 0x0000ffff) << 16) + (skb->len - 4);
+ cpu_to_le32s(&packet_len);
+ skb_copy_to_linear_data(skb, &packet_len, sizeof(packet_len));
+
+ if (padlen) {
+ cpu_to_le32s(&padbytes);
+ memcpy(skb_tail_pointer(skb), &padbytes, sizeof(padbytes));
+ skb_put(skb, sizeof(padbytes));
+ }
+
+ return skb;
+}
+
+static void sr_status(struct usbnet *dev, struct urb *urb)
+{
+ struct sr9800_int_data *event;
+ int link;
+
+ if (urb->actual_length < 8)
+ return;
+
+ event = urb->transfer_buffer;
+ link = event->link & 0x01;
+ if (netif_carrier_ok(dev->net) != link) {
+ usbnet_link_change(dev, link, 1);
+ netdev_dbg(dev->net, "Link Status is: %d\n", link);
+ }
+
+ return;
+}
+
+static inline int sr_set_sw_mii(struct usbnet *dev)
+{
+ int ret;
+
+ ret = sr_write_cmd(dev, SR_CMD_SET_SW_MII, 0x0000, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net, "Failed to enable software MII access\n");
+ return ret;
+}
+
+static inline int sr_set_hw_mii(struct usbnet *dev)
+{
+ int ret;
+
+ ret = sr_write_cmd(dev, SR_CMD_SET_HW_MII, 0x0000, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net, "Failed to enable hardware MII access\n");
+ return ret;
+}
+
+static inline int sr_get_phy_addr(struct usbnet *dev)
+{
+ u8 buf[2];
+ int ret;
+
+ ret = sr_read_cmd(dev, SR_CMD_READ_PHY_ID, 0, 0, 2, buf);
+ if (ret < 0) {
+ netdev_err(dev->net, "Error reading PHYID register:%02x\n",
+ ret);
+ goto out;
+ }
+ netdev_dbg(dev->net, "sr_get_phy_addr() returning 0x%04x\n",
+ *((__le16 *)buf));
+
+ ret = buf[1];
+
+out:
+ return ret;
+}
+
+static int sr_sw_reset(struct usbnet *dev, u8 flags)
+{
+ int ret;
+
+ ret = sr_write_cmd(dev, SR_CMD_SW_RESET, flags, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net, "Failed to send software reset:%02x\n",
+ ret);
+
+ return ret;
+}
+
+static u16 sr_read_rx_ctl(struct usbnet *dev)
+{
+ __le16 v;
+ int ret;
+
+ ret = sr_read_cmd(dev, SR_CMD_READ_RX_CTL, 0, 0, 2, &v);
+ if (ret < 0) {
+ netdev_err(dev->net, "Error reading RX_CTL register:%02x\n",
+ ret);
+ goto out;
+ }
+
+ ret = le16_to_cpu(v);
+out:
+ return ret;
+}
+
+static int sr_write_rx_ctl(struct usbnet *dev, u16 mode)
+{
+ int ret;
+
+ netdev_dbg(dev->net, "sr_write_rx_ctl() - mode = 0x%04x\n", mode);
+ ret = sr_write_cmd(dev, SR_CMD_WRITE_RX_CTL, mode, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net,
+ "Failed to write RX_CTL mode to 0x%04x:%02x\n",
+ mode, ret);
+
+ return ret;
+}
+
+static u16 sr_read_medium_status(struct usbnet *dev)
+{
+ __le16 v;
+ int ret;
+
+ ret = sr_read_cmd(dev, SR_CMD_READ_MEDIUM_STATUS, 0, 0, 2, &v);
+ if (ret < 0) {
+ netdev_err(dev->net,
+ "Error reading Medium Status register:%02x\n", ret);
+ return ret; /* TODO: callers not checking for error ret */
+ }
+
+ return le16_to_cpu(v);
+}
+
+static int sr_write_medium_mode(struct usbnet *dev, u16 mode)
+{
+ int ret;
+
+ netdev_dbg(dev->net, "sr_write_medium_mode() - mode = 0x%04x\n", mode);
+ ret = sr_write_cmd(dev, SR_CMD_WRITE_MEDIUM_MODE, mode, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net,
+ "Failed to write Medium Mode mode to 0x%04x:%02x\n",
+ mode, ret);
+ return ret;
+}
+
+static int sr_write_gpio(struct usbnet *dev, u16 value, int sleep)
+{
+ int ret;
+
+ netdev_dbg(dev->net, "sr_write_gpio() - value = 0x%04x\n", value);
+ ret = sr_write_cmd(dev, SR_CMD_WRITE_GPIOS, value, 0, 0, NULL);
+ if (ret < 0)
+ netdev_err(dev->net, "Failed to write GPIO value 0x%04x:%02x\n",
+ value, ret);
+ if (sleep)
+ msleep(sleep);
+
+ return ret;
+}
+
+/* SR9800 have a 16-bit RX_CTL value */
+static void sr_set_multicast(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sr_data *data = (struct sr_data *)&dev->data;
+ u16 rx_ctl = SR_DEFAULT_RX_CTL;
+
+ if (net->flags & IFF_PROMISC) {
+ rx_ctl |= SR_RX_CTL_PRO;
+ } else if (net->flags & IFF_ALLMULTI ||
+ netdev_mc_count(net) > SR_MAX_MCAST) {
+ rx_ctl |= SR_RX_CTL_AMALL;
+ } else if (netdev_mc_empty(net)) {
+ /* just broadcast and directed */
+ } else {
+ /* We use the 20 byte dev->data
+ * for our 8 byte filter buffer
+ * to avoid allocating memory that
+ * is tricky to free later
+ */
+ struct netdev_hw_addr *ha;
+ u32 crc_bits;
+
+ memset(data->multi_filter, 0, SR_MCAST_FILTER_SIZE);
+
+ /* Build the multicast hash filter. */
+ netdev_for_each_mc_addr(ha, net) {
+ crc_bits = ether_crc(ETH_ALEN, ha->addr) >> 26;
+ data->multi_filter[crc_bits >> 3] |=
+ 1 << (crc_bits & 7);
+ }
+
+ sr_write_cmd_async(dev, SR_CMD_WRITE_MULTI_FILTER, 0, 0,
+ SR_MCAST_FILTER_SIZE, data->multi_filter);
+
+ rx_ctl |= SR_RX_CTL_AM;
+ }
+
+ sr_write_cmd_async(dev, SR_CMD_WRITE_RX_CTL, rx_ctl, 0, 0, NULL);
+}
+
+static int sr_mdio_read(struct net_device *net, int phy_id, int loc)
+{
+ struct usbnet *dev = netdev_priv(net);
+ __le16 res;
+
+ mutex_lock(&dev->phy_mutex);
+ sr_set_sw_mii(dev);
+ sr_read_cmd(dev, SR_CMD_READ_MII_REG, phy_id, (__u16)loc, 2, &res);
+ sr_set_hw_mii(dev);
+ mutex_unlock(&dev->phy_mutex);
+
+ netdev_dbg(dev->net,
+ "sr_mdio_read() phy_id=0x%02x, loc=0x%02x, returns=0x%04x\n",
+ phy_id, loc, le16_to_cpu(res));
+
+ return le16_to_cpu(res);
+}
+
+static void
+sr_mdio_write(struct net_device *net, int phy_id, int loc, int val)
+{
+ struct usbnet *dev = netdev_priv(net);
+ __le16 res = cpu_to_le16(val);
+
+ netdev_dbg(dev->net,
+ "sr_mdio_write() phy_id=0x%02x, loc=0x%02x, val=0x%04x\n",
+ phy_id, loc, val);
+ mutex_lock(&dev->phy_mutex);
+ sr_set_sw_mii(dev);
+ sr_write_cmd(dev, SR_CMD_WRITE_MII_REG, phy_id, (__u16)loc, 2, &res);
+ sr_set_hw_mii(dev);
+ mutex_unlock(&dev->phy_mutex);
+}
+
+/* Get the PHY Identifier from the PHYSID1 & PHYSID2 MII registers */
+static u32 sr_get_phyid(struct usbnet *dev)
+{
+ int phy_reg;
+ u32 phy_id;
+ int i;
+
+ /* Poll for the rare case the FW or phy isn't ready yet. */
+ for (i = 0; i < 100; i++) {
+ phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID1);
+ if (phy_reg != 0 && phy_reg != 0xFFFF)
+ break;
+ mdelay(1);
+ }
+
+ if (phy_reg <= 0 || phy_reg == 0xFFFF)
+ return 0;
+
+ phy_id = (phy_reg & 0xffff) << 16;
+
+ phy_reg = sr_mdio_read(dev->net, dev->mii.phy_id, MII_PHYSID2);
+ if (phy_reg < 0)
+ return 0;
+
+ phy_id |= (phy_reg & 0xffff);
+
+ return phy_id;
+}
+
+static void
+sr_get_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+{
+ struct usbnet *dev = netdev_priv(net);
+ u8 opt;
+
+ if (sr_read_cmd(dev, SR_CMD_READ_MONITOR_MODE, 0, 0, 1, &opt) < 0) {
+ wolinfo->supported = 0;
+ wolinfo->wolopts = 0;
+ return;
+ }
+ wolinfo->supported = WAKE_PHY | WAKE_MAGIC;
+ wolinfo->wolopts = 0;
+ if (opt & SR_MONITOR_LINK)
+ wolinfo->wolopts |= WAKE_PHY;
+ if (opt & SR_MONITOR_MAGIC)
+ wolinfo->wolopts |= WAKE_MAGIC;
+}
+
+static int
+sr_set_wol(struct net_device *net, struct ethtool_wolinfo *wolinfo)
+{
+ struct usbnet *dev = netdev_priv(net);
+ u8 opt = 0;
+
+ if (wolinfo->wolopts & WAKE_PHY)
+ opt |= SR_MONITOR_LINK;
+ if (wolinfo->wolopts & WAKE_MAGIC)
+ opt |= SR_MONITOR_MAGIC;
+
+ if (sr_write_cmd(dev, SR_CMD_WRITE_MONITOR_MODE,
+ opt, 0, 0, NULL) < 0)
+ return -EINVAL;
+
+ return 0;
+}
+
+static int sr_get_eeprom_len(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sr_data *data = (struct sr_data *)&dev->data;
+
+ return data->eeprom_len;
+}
+
+static int sr_get_eeprom(struct net_device *net,
+ struct ethtool_eeprom *eeprom, u8 *data)
+{
+ struct usbnet *dev = netdev_priv(net);
+ __le16 *ebuf = (__le16 *)data;
+ int ret;
+ int i;
+
+ /* Crude hack to ensure that we don't overwrite memory
+ * if an odd length is supplied
+ */
+ if (eeprom->len % 2)
+ return -EINVAL;
+
+ eeprom->magic = SR_EEPROM_MAGIC;
+
+ /* sr9800 returns 2 bytes from eeprom on read */
+ for (i = 0; i < eeprom->len / 2; i++) {
+ ret = sr_read_cmd(dev, SR_CMD_READ_EEPROM, eeprom->offset + i,
+ 0, 2, &ebuf[i]);
+ if (ret < 0)
+ return -EINVAL;
+ }
+ return 0;
+}
+
+static void sr_get_drvinfo(struct net_device *net,
+ struct ethtool_drvinfo *info)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sr_data *data = (struct sr_data *)&dev->data;
+
+ /* Inherit standard device info */
+ usbnet_get_drvinfo(net, info);
+ strncpy(info->driver, DRIVER_NAME, sizeof(info->driver));
+ strncpy(info->version, DRIVER_VERSION, sizeof(info->version));
+ info->eedump_len = data->eeprom_len;
+}
+
+static u32 sr_get_link(struct net_device *net)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return mii_link_ok(&dev->mii);
+}
+
+static int sr_ioctl(struct net_device *net, struct ifreq *rq, int cmd)
+{
+ struct usbnet *dev = netdev_priv(net);
+
+ return generic_mii_ioctl(&dev->mii, if_mii(rq), cmd, NULL);
+}
+
+static int sr_set_mac_address(struct net_device *net, void *p)
+{
+ struct usbnet *dev = netdev_priv(net);
+ struct sr_data *data = (struct sr_data *)&dev->data;
+ struct sockaddr *addr = p;
+
+ if (netif_running(net))
+ return -EBUSY;
+ if (!is_valid_ether_addr(addr->sa_data))
+ return -EADDRNOTAVAIL;
+
+ memcpy(net->dev_addr, addr->sa_data, ETH_ALEN);
+
+ /* We use the 20 byte dev->data
+ * for our 6 byte mac buffer
+ * to avoid allocating memory that
+ * is tricky to free later
+ */
+ memcpy(data->mac_addr, addr->sa_data, ETH_ALEN);
+ sr_write_cmd_async(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+ data->mac_addr);
+
+ return 0;
+}
+
+static const struct ethtool_ops sr9800_ethtool_ops = {
+ .get_drvinfo = sr_get_drvinfo,
+ .get_link = sr_get_link,
+ .get_msglevel = usbnet_get_msglevel,
+ .set_msglevel = usbnet_set_msglevel,
+ .get_wol = sr_get_wol,
+ .set_wol = sr_set_wol,
+ .get_eeprom_len = sr_get_eeprom_len,
+ .get_eeprom = sr_get_eeprom,
+ .get_settings = usbnet_get_settings,
+ .set_settings = usbnet_set_settings,
+ .nway_reset = usbnet_nway_reset,
+};
+
+static int sr9800_link_reset(struct usbnet *dev)
+{
+ struct ethtool_cmd ecmd = { .cmd = ETHTOOL_GSET };
+ u16 mode;
+
+ mii_check_media(&dev->mii, 1, 1);
+ mii_ethtool_gset(&dev->mii, &ecmd);
+ mode = SR9800_MEDIUM_DEFAULT;
+
+ if (ethtool_cmd_speed(&ecmd) != SPEED_100)
+ mode &= ~SR_MEDIUM_PS;
+
+ if (ecmd.duplex != DUPLEX_FULL)
+ mode &= ~SR_MEDIUM_FD;
+
+ netdev_dbg(dev->net, "link_reset speed: %u duplex: %d mode: 0x%04x\n",
+ ethtool_cmd_speed(&ecmd), ecmd.duplex, mode);
+
+ sr_write_medium_mode(dev, mode);
+
+ return 0;
+}
+
+
+static inline int sr9800_set_default_mode(struct usbnet *dev)
+{
+ u16 rx_ctl;
+ int ret;
+
+ sr_mdio_write(dev->net, dev->mii.phy_id, MII_BMCR, BMCR_RESET);
+ sr_mdio_write(dev->net, dev->mii.phy_id, MII_ADVERTISE,
+ ADVERTISE_ALL | ADVERTISE_CSMA);
+ mii_nway_restart(&dev->mii);
+
+ ret = sr_write_medium_mode(dev, SR9800_MEDIUM_DEFAULT);
+ if (ret < 0)
+ goto out;
+
+ ret = sr_write_cmd(dev, SR_CMD_WRITE_IPG012,
+ SR9800_IPG0_DEFAULT | SR9800_IPG1_DEFAULT,
+ SR9800_IPG2_DEFAULT, 0, NULL);
+ if (ret < 0) {
+ netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d", ret);
+ goto out;
+ }
+
+ /* Set RX_CTL to default values with 2k buffer, and enable cactus */
+ ret = sr_write_rx_ctl(dev, SR_DEFAULT_RX_CTL);
+ if (ret < 0)
+ goto out;
+
+ rx_ctl = sr_read_rx_ctl(dev);
+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations",
+ rx_ctl);
+
+ rx_ctl = sr_read_medium_status(dev);
+ netdev_dbg(dev->net, "Medium Status : 0x%04x after all initializations",
+ rx_ctl);
+
+ return 0;
+out:
+ return ret;
+}
+
+static int sr9800_reset(struct usbnet *dev)
+{
+ struct sr_data *data = (struct sr_data *)&dev->data;
+ int ret, embd_phy;
+ u16 rx_ctl;
+
+ ret = sr_write_gpio(dev,
+ SR_GPIO_RSE | SR_GPIO_GPO_2 | SR_GPIO_GPO2EN, 5);
+ if (ret < 0)
+ goto out;
+
+ embd_phy = ((sr_get_phy_addr(dev) & 0x1f) == 0x10 ? 1 : 0);
+
+ ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
+ if (ret < 0) {
+ netdev_dbg(dev->net, "Select PHY #1 failed: %d", ret);
+ goto out;
+ }
+
+ ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_PRL);
+ if (ret < 0)
+ goto out;
+
+ msleep(150);
+
+ ret = sr_sw_reset(dev, SR_SWRESET_CLEAR);
+ if (ret < 0)
+ goto out;
+
+ msleep(150);
+
+ if (embd_phy) {
+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
+ if (ret < 0)
+ goto out;
+ } else {
+ ret = sr_sw_reset(dev, SR_SWRESET_PRTE);
+ if (ret < 0)
+ goto out;
+ }
+
+ msleep(150);
+ rx_ctl = sr_read_rx_ctl(dev);
+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset", rx_ctl);
+ ret = sr_write_rx_ctl(dev, 0x0000);
+ if (ret < 0)
+ goto out;
+
+ rx_ctl = sr_read_rx_ctl(dev);
+ netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000", rx_ctl);
+
+ ret = sr_sw_reset(dev, SR_SWRESET_PRL);
+ if (ret < 0)
+ goto out;
+
+ msleep(150);
+
+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL | SR_SWRESET_PRL);
+ if (ret < 0)
+ goto out;
+
+ msleep(150);
+
+ ret = sr9800_set_default_mode(dev);
+ if (ret < 0)
+ goto out;
+
+ /* Rewrite MAC address */
+ memcpy(data->mac_addr, dev->net->dev_addr, ETH_ALEN);
+ ret = sr_write_cmd(dev, SR_CMD_WRITE_NODE_ID, 0, 0, ETH_ALEN,
+ data->mac_addr);
+ if (ret < 0)
+ goto out;
+
+ return 0;
+
+out:
+ return ret;
+}
+
+static const struct net_device_ops sr9800_netdev_ops = {
+ .ndo_open = usbnet_open,
+ .ndo_stop = usbnet_stop,
+ .ndo_start_xmit = usbnet_start_xmit,
+ .ndo_tx_timeout = usbnet_tx_timeout,
+ .ndo_change_mtu = usbnet_change_mtu,
+ .ndo_set_mac_address = sr_set_mac_address,
+ .ndo_validate_addr = eth_validate_addr,
+ .ndo_do_ioctl = sr_ioctl,
+ .ndo_set_rx_mode = sr_set_multicast,
+};
+
+static int sr9800_phy_powerup(struct usbnet *dev)
+{
+ int ret;
+
+ /* set the embedded Ethernet PHY in power-down state */
+ ret = sr_sw_reset(dev, SR_SWRESET_IPPD | SR_SWRESET_IPRL);
+ if (ret < 0) {
+ netdev_err(dev->net, "Failed to power down PHY : %d", ret);
+ return ret;
+ }
+ msleep(20);
+
+ /* set the embedded Ethernet PHY in power-up state */
+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
+ if (ret < 0) {
+ netdev_err(dev->net, "Failed to reset PHY: %d", ret);
+ return ret;
+ }
+ msleep(600);
+
+ /* set the embedded Ethernet PHY in reset state */
+ ret = sr_sw_reset(dev, SR_SWRESET_CLEAR);
+ if (ret < 0) {
+ netdev_err(dev->net, "Failed to power up PHY: %d", ret);
+ return ret;
+ }
+ msleep(20);
+
+ /* set the embedded Ethernet PHY in power-up state */
+ ret = sr_sw_reset(dev, SR_SWRESET_IPRL);
+ if (ret < 0) {
+ netdev_err(dev->net, "Failed to reset PHY: %d", ret);
+ return ret;
+ }
+
+ return 0;
+}
+
+static int sr9800_bind(struct usbnet *dev, struct usb_interface *intf)
+{
+ struct sr_data *data = (struct sr_data *)&dev->data;
+ u16 led01_mux, led23_mux;
+ int ret, embd_phy;
+ u32 phyid;
+ u16 rx_ctl;
+
+ data->eeprom_len = SR9800_EEPROM_LEN;
+
+ usbnet_get_endpoints(dev, intf);
+
+ /* LED Setting Rule :
+ * AABB:CCDD
+ * AA : MFA0(LED0)
+ * BB : MFA1(LED1)
+ * CC : MFA2(LED2), Reserved for SR9800
+ * DD : MFA3(LED3), Reserved for SR9800
+ */
+ led01_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_LINK;
+ led23_mux = (SR_LED_MUX_LINK_ACTIVE << 8) | SR_LED_MUX_TX_ACTIVE;
+ ret = sr_write_cmd(dev, SR_CMD_LED_MUX, led01_mux, led23_mux, 0, NULL);
+ if (ret < 0) {
+ netdev_err(dev->net, "set LINK LED failed : %d", ret);
+ goto out;
+ }
+
+ /* Get the MAC address */
+ ret = sr_read_cmd(dev, SR_CMD_READ_NODE_ID, 0, 0, ETH_ALEN,
+ dev->net->dev_addr);
+ if (ret < 0) {
+ netdev_dbg(dev->net, "Failed to read MAC address: %d", ret);
+ return ret;
+ }
+ netdev_dbg(dev->net, "mac addr : 0x%x:0x%x:0x%x:0x%x:0x%x:0x%x\n",
+ dev->net->dev_addr[0], dev->net->dev_addr[1],
+ dev->net->dev_addr[2], dev->net->dev_addr[3],
+ dev->net->dev_addr[4], dev->net->dev_addr[5]);
+
+ /* Initialize MII structure */
+ dev->mii.dev = dev->net;
+ dev->mii.mdio_read = sr_mdio_read;
+ dev->mii.mdio_write = sr_mdio_write;
+ dev->mii.phy_id_mask = 0x1f;
+ dev->mii.reg_num_mask = 0x1f;
+ dev->mii.phy_id = sr_get_phy_addr(dev);
+
+ dev->net->netdev_ops = &sr9800_netdev_ops;
+ dev->net->ethtool_ops = &sr9800_ethtool_ops;
+
+ embd_phy = ((dev->mii.phy_id & 0x1f) == 0x10 ? 1 : 0);
+ /* Reset the PHY to normal operation mode */
+ ret = sr_write_cmd(dev, SR_CMD_SW_PHY_SELECT, embd_phy, 0, 0, NULL);
+ if (ret < 0) {
+ netdev_dbg(dev->net, "Select PHY #1 failed: %d", ret);
+ return ret;
+ }
+
+ /* Init PHY routine */
+ ret = sr9800_phy_powerup(dev);
+ if (ret < 0)
+ goto out;
+
+ rx_ctl = sr_read_rx_ctl(dev);
+ netdev_dbg(dev->net, "RX_CTL is 0x%04x after software reset", rx_ctl);
+ ret = sr_write_rx_ctl(dev, 0x0000);
+ if (ret < 0)
+ goto out;
+
+ rx_ctl = sr_read_rx_ctl(dev);
+ netdev_dbg(dev->net, "RX_CTL is 0x%04x setting to 0x0000", rx_ctl);
+
+ /* Read PHYID register *AFTER* the PHY was reset properly */
+ phyid = sr_get_phyid(dev);
+ netdev_dbg(dev->net, "PHYID=0x%08x", phyid);
+
+ /* medium mode setting */
+ ret = sr9800_set_default_mode(dev);
+ if (ret < 0)
+ goto out;
+
+ if (dev->udev->speed == USB_SPEED_HIGH) {
+ ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE,
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].byte_cnt,
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].threshold,
+ 0, NULL);
+ if (ret < 0) {
+ netdev_err(dev->net, "Reset RX_CTL failed: %d", ret);
+ goto out;
+ }
+ dev->rx_urb_size =
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_4K].size;
+ } else {
+ ret = sr_write_cmd(dev, SR_CMD_BULKIN_SIZE,
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].byte_cnt,
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].threshold,
+ 0, NULL);
+ if (ret < 0) {
+ netdev_err(dev->net, "Reset RX_CTL failed: %d", ret);
+ goto out;
+ }
+ dev->rx_urb_size =
+ SR9800_BULKIN_SIZE[SR9800_MAX_BULKIN_2K].size;
+ }
+ netdev_dbg(dev->net, "sr9800_bind : setting rx_urb_size with : %ld\n",
+ dev->rx_urb_size);
+ return 0;
+
+out:
+ return ret;
+}
+
+static const struct driver_info sr9800_driver_info = {
+ .description = "CoreChip SR9800 USB 2.0 Ethernet",
+ .bind = sr9800_bind,
+ .status = sr_status,
+ .link_reset = sr9800_link_reset,
+ .reset = sr9800_reset,
+ .flags = DRIVER_FLAG,
+ .rx_fixup = sr_rx_fixup,
+ .tx_fixup = sr_tx_fixup,
+};
+
+static const struct usb_device_id products[] = {
+ {
+ USB_DEVICE(0x0fe6, 0x9800), /* SR9800 Device */
+ .driver_info = (unsigned long) &sr9800_driver_info,
+ },
+ {}, /* END */
+};
+
+MODULE_DEVICE_TABLE(usb, products);
+
+static struct usb_driver sr_driver = {
+ .name = DRIVER_NAME,
+ .id_table = products,
+ .probe = usbnet_probe,
+ .suspend = usbnet_suspend,
+ .resume = usbnet_resume,
+ .disconnect = usbnet_disconnect,
+ .supports_autosuspend = 1,
+};
+
+module_usb_driver(sr_driver);
+
+MODULE_AUTHOR("Liu Junliang <liujunliang_ljl@163.com");
+MODULE_VERSION(DRIVER_VERSION);
+MODULE_DESCRIPTION("SR9800 USB 2.0 USB2NET Dev : http://www.corechip-sz.com");
+MODULE_LICENSE("GPL");
+
diff --git a/drivers/net/usb/sr9800.h b/drivers/net/usb/sr9800.h
new file mode 100644
index 0000000..18f6702
--- /dev/null
+++ b/drivers/net/usb/sr9800.h
@@ -0,0 +1,202 @@
+/* CoreChip-sz SR9800 one chip USB 2.0 Ethernet Devices
+ *
+ * Author : Liu Junliang <liujunliang_ljl@163.com>
+ *
+ * This file is licensed under the terms of the GNU General Public License
+ * version 2. This program is licensed "as is" without any warranty of any
+ * kind, whether express or implied.
+ */
+
+#ifndef _SR9800_H
+#define _SR9800_H
+
+/* SR9800 spec. command table on Linux Platform */
+
+/* command : Software Station Management Control Reg */
+#define SR_CMD_SET_SW_MII 0x06
+/* command : PHY Read Reg */
+#define SR_CMD_READ_MII_REG 0x07
+/* command : PHY Write Reg */
+#define SR_CMD_WRITE_MII_REG 0x08
+/* command : Hardware Station Management Control Reg */
+#define SR_CMD_SET_HW_MII 0x0a
+/* command : SROM Read Reg */
+#define SR_CMD_READ_EEPROM 0x0b
+/* command : SROM Write Reg */
+#define SR_CMD_WRITE_EEPROM 0x0c
+/* command : SROM Write Enable Reg */
+#define SR_CMD_WRITE_ENABLE 0x0d
+/* command : SROM Write Disable Reg */
+#define SR_CMD_WRITE_DISABLE 0x0e
+/* command : RX Control Read Reg */
+#define SR_CMD_READ_RX_CTL 0x0f
+#define SR_RX_CTL_PRO (1 << 0)
+#define SR_RX_CTL_AMALL (1 << 1)
+#define SR_RX_CTL_SEP (1 << 2)
+#define SR_RX_CTL_AB (1 << 3)
+#define SR_RX_CTL_AM (1 << 4)
+#define SR_RX_CTL_AP (1 << 5)
+#define SR_RX_CTL_ARP (1 << 6)
+#define SR_RX_CTL_SO (1 << 7)
+#define SR_RX_CTL_RH1M (1 << 8)
+#define SR_RX_CTL_RH2M (1 << 9)
+#define SR_RX_CTL_RH3M (1 << 10)
+/* command : RX Control Write Reg */
+#define SR_CMD_WRITE_RX_CTL 0x10
+/* command : IPG0/IPG1/IPG2 Control Read Reg */
+#define SR_CMD_READ_IPG012 0x11
+/* command : IPG0/IPG1/IPG2 Control Write Reg */
+#define SR_CMD_WRITE_IPG012 0x12
+/* command : Node ID Read Reg */
+#define SR_CMD_READ_NODE_ID 0x13
+/* command : Node ID Write Reg */
+#define SR_CMD_WRITE_NODE_ID 0x14
+/* command : Multicast Filter Array Read Reg */
+#define SR_CMD_READ_MULTI_FILTER 0x15
+/* command : Multicast Filter Array Write Reg */
+#define SR_CMD_WRITE_MULTI_FILTER 0x16
+/* command : Eth/HomePNA PHY Address Reg */
+#define SR_CMD_READ_PHY_ID 0x19
+/* command : Medium Status Read Reg */
+#define SR_CMD_READ_MEDIUM_STATUS 0x1a
+#define SR_MONITOR_LINK (1 << 1)
+#define SR_MONITOR_MAGIC (1 << 2)
+#define SR_MONITOR_HSFS (1 << 4)
+/* command : Medium Status Write Reg */
+#define SR_CMD_WRITE_MEDIUM_MODE 0x1b
+#define SR_MEDIUM_GM (1 << 0)
+#define SR_MEDIUM_FD (1 << 1)
+#define SR_MEDIUM_AC (1 << 2)
+#define SR_MEDIUM_ENCK (1 << 3)
+#define SR_MEDIUM_RFC (1 << 4)
+#define SR_MEDIUM_TFC (1 << 5)
+#define SR_MEDIUM_JFE (1 << 6)
+#define SR_MEDIUM_PF (1 << 7)
+#define SR_MEDIUM_RE (1 << 8)
+#define SR_MEDIUM_PS (1 << 9)
+#define SR_MEDIUM_RSV (1 << 10)
+#define SR_MEDIUM_SBP (1 << 11)
+#define SR_MEDIUM_SM (1 << 12)
+/* command : Monitor Mode Status Read Reg */
+#define SR_CMD_READ_MONITOR_MODE 0x1c
+/* command : Monitor Mode Status Write Reg */
+#define SR_CMD_WRITE_MONITOR_MODE 0x1d
+/* command : GPIO Status Read Reg */
+#define SR_CMD_READ_GPIOS 0x1e
+#define SR_GPIO_GPO0EN (1 << 0) /* GPIO0 Output enable */
+#define SR_GPIO_GPO_0 (1 << 1) /* GPIO0 Output value */
+#define SR_GPIO_GPO1EN (1 << 2) /* GPIO1 Output enable */
+#define SR_GPIO_GPO_1 (1 << 3) /* GPIO1 Output value */
+#define SR_GPIO_GPO2EN (1 << 4) /* GPIO2 Output enable */
+#define SR_GPIO_GPO_2 (1 << 5) /* GPIO2 Output value */
+#define SR_GPIO_RESERVED (1 << 6) /* Reserved */
+#define SR_GPIO_RSE (1 << 7) /* Reload serial EEPROM */
+/* command : GPIO Status Write Reg */
+#define SR_CMD_WRITE_GPIOS 0x1f
+/* command : Eth PHY Power and Reset Control Reg */
+#define SR_CMD_SW_RESET 0x20
+#define SR_SWRESET_CLEAR 0x00
+#define SR_SWRESET_RR (1 << 0)
+#define SR_SWRESET_RT (1 << 1)
+#define SR_SWRESET_PRTE (1 << 2)
+#define SR_SWRESET_PRL (1 << 3)
+#define SR_SWRESET_BZ (1 << 4)
+#define SR_SWRESET_IPRL (1 << 5)
+#define SR_SWRESET_IPPD (1 << 6)
+/* command : Software Interface Selection Status Read Reg */
+#define SR_CMD_SW_PHY_STATUS 0x21
+/* command : Software Interface Selection Status Write Reg */
+#define SR_CMD_SW_PHY_SELECT 0x22
+/* command : BULK in Buffer Size Reg */
+#define SR_CMD_BULKIN_SIZE 0x2A
+/* command : LED_MUX Control Reg */
+#define SR_CMD_LED_MUX 0x70
+#define SR_LED_MUX_TX_ACTIVE (1 << 0)
+#define SR_LED_MUX_RX_ACTIVE (1 << 1)
+#define SR_LED_MUX_COLLISION (1 << 2)
+#define SR_LED_MUX_DUP_COL (1 << 3)
+#define SR_LED_MUX_DUP (1 << 4)
+#define SR_LED_MUX_SPEED (1 << 5)
+#define SR_LED_MUX_LINK_ACTIVE (1 << 6)
+#define SR_LED_MUX_LINK (1 << 7)
+
+/* Register Access Flags */
+#define SR_REQ_RD_REG (USB_DIR_IN | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+#define SR_REQ_WR_REG (USB_DIR_OUT | USB_TYPE_VENDOR | USB_RECIP_DEVICE)
+
+/* Multicast Filter Array size & Max Number */
+#define SR_MCAST_FILTER_SIZE 8
+#define SR_MAX_MCAST 64
+
+/* IPG0/1/2 Default Value */
+#define SR9800_IPG0_DEFAULT 0x15
+#define SR9800_IPG1_DEFAULT 0x0c
+#define SR9800_IPG2_DEFAULT 0x12
+
+/* Medium Status Default Mode */
+#define SR9800_MEDIUM_DEFAULT \
+ (SR_MEDIUM_FD | SR_MEDIUM_RFC | \
+ SR_MEDIUM_TFC | SR_MEDIUM_PS | \
+ SR_MEDIUM_AC | SR_MEDIUM_RE)
+
+/* RX Control Default Setting */
+#define SR_DEFAULT_RX_CTL \
+ (SR_RX_CTL_SO | SR_RX_CTL_AB | SR_RX_CTL_RH1M)
+
+/* EEPROM Magic Number & EEPROM Size */
+#define SR_EEPROM_MAGIC 0xdeadbeef
+#define SR9800_EEPROM_LEN 0xff
+
+/* SR9800 Driver Version and Driver Name */
+#define DRIVER_VERSION "11-Nov-2013"
+#define DRIVER_NAME "CoreChips"
+#define DRIVER_FLAG \
+ (FLAG_ETHER | FLAG_FRAMING_AX | FLAG_LINK_INTR | FLAG_MULTI_PACKET)
+
+/* SR9800 BULKIN Buffer Size */
+#define SR9800_MAX_BULKIN_2K 0
+#define SR9800_MAX_BULKIN_4K 1
+#define SR9800_MAX_BULKIN_6K 2
+#define SR9800_MAX_BULKIN_8K 3
+#define SR9800_MAX_BULKIN_16K 4
+#define SR9800_MAX_BULKIN_20K 5
+#define SR9800_MAX_BULKIN_24K 6
+#define SR9800_MAX_BULKIN_32K 7
+
+struct {unsigned short size, byte_cnt, threshold; } SR9800_BULKIN_SIZE[] = {
+ /* 2k */
+ {2048, 0x8000, 0x8001},
+ /* 4k */
+ {4096, 0x8100, 0x8147},
+ /* 6k */
+ {6144, 0x8200, 0x81EB},
+ /* 8k */
+ {8192, 0x8300, 0x83D7},
+ /* 16 */
+ {16384, 0x8400, 0x851E},
+ /* 20k */
+ {20480, 0x8500, 0x8666},
+ /* 24k */
+ {24576, 0x8600, 0x87AE},
+ /* 32k */
+ {32768, 0x8700, 0x8A3D},
+};
+
+/* This structure cannot exceed sizeof(unsigned long [5]) AKA 20 bytes */
+struct sr_data {
+ u8 multi_filter[SR_MCAST_FILTER_SIZE];
+ u8 mac_addr[ETH_ALEN];
+ u8 phymode;
+ u8 ledmode;
+ u8 eeprom_len;
+};
+
+struct sr9800_int_data {
+ __le16 res1;
+ u8 link;
+ __le16 res2;
+ u8 status;
+ __le16 res3;
+} __packed;
+
+#endif /* _SR9800_H */
--
1.7.9.5
^ permalink raw reply related
* Re: 8% performance improved by change tap interact with kernel stack
From: Michael S. Tsirkin @ 2014-01-28 8:34 UTC (permalink / raw)
To: Qin Chuanyu; +Cc: jasowang, Anthony Liguori, KVM list, netdev
In-Reply-To: <52E766D4.4070901@huawei.com>
On Tue, Jan 28, 2014 at 04:14:12PM +0800, Qin Chuanyu wrote:
> according perf test result,I found that there are 5%-8% cpu cost on
> softirq by use netif_rx_ni called in tun_get_user.
>
> so I changed the function which cause skb transmitted more quickly.
> from
> tun_get_user ->
> netif_rx_ni(skb);
> to
> tun_get_user ->
> rcu_read_lock_bh();
> netif_receive_skb(skb);
> rcu_read_unlock_bh();
>
> The test result is as below:
> CPU: Intel(R) Xeon(R) CPU E5620 @ 2.40GHz
> NIC: intel 82599
> Host OS/Guest OS:suse11sp3
> Qemu-1.6
> netperf udp 512(VM tx)
> test model: VM->host->host
>
> modified before : 2.00Gbps 461146pps
> modified after : 2.16Gbps 498782pps
>
> 8% performance gained from this change,
> Is there any problem for this patch ?
I think it's okay - IIUC this way we are processing xmit directly
instead of going through softirq.
Was meaning to try this - I'm glad you are looking into this.
Could you please check latency results?
--
MST
^ permalink raw reply
* Re: [PATCH 2/2] net: ip, ipv6: handle gso skbs in forwarding path
From: Florian Westphal @ 2014-01-28 8:57 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Florian Westphal, netdev
In-Reply-To: <1390846967.27806.75.camel@edumazet-glaptop2.roam.corp.google.com>
Eric Dumazet <eric.dumazet@gmail.com> wrote:
> > + do {
> > + struct sk_buff *nskb = segs->next;
> > + int err;
> > +
> > + segs->next = NULL;
> > + err = dst_output(segs);
> > +
> > + if (err && ret == 0)
> > + ret = err;
> > + segs = nskb;
> > + } while (segs);
> > +
> > + return ret;
> > +}
> > +
>
> Its still unclear if this is the best strategy.
>
> TCP stream not using DF flag are very unlikely to care if we adjust
> their MTU (lowering gso_size) at this point ?
Thanks for this suggestion. It would indeed be nice to avoid sw
segmentation. I tried:
static void ip_gso_adjust_seglen(struct sk_buff *skb)
{
unsigned int mtu;
if (!skb_is_gso(skb))
return;
mtu = ip_dst_mtu_maybe_forward(skb_dst(skb), true);
skb_shinfo(skb)->gso_size = mtu - sizeof(struct iphdr);
}
But this yields
[ 28.644776] kernel BUG at net/net/core/skbuff.c:2984!
[ 28.644776] invalid opcode: 0000 [#1] SMP
[ 28.644776] CPU: 0 PID: 0 Comm: swapper/0 Not tainted 3.13.0+ #35
[ 28.644776] task: ffffffff818104c0 ti: ffffffff81800000 task.ti: ffffffff81800000
[ 28.644776] RIP: 0010:[<ffffffff813b10d8>] [<ffffffff813b10d8>] skb_segment+0x808/0x830
[ 28.644776] RSP: 0018:ffff88002fc03688 EFLAGS: 00010212
[ 28.644776] RAX: 000000000000047c RBX: ffff88002d614b00 RCX: ffff88002d72ab00
[ 28.644776] RDX: 000000000000047c RSI: 00000000000050fa RDI: ffff88002cf9f800
[ 28.644776] RBP: ffff88002fc03778 R08: 0000000000000000 R09: ffff88002cdaf300
[ 28.644776] R10: 0000000000000011 R11: 0000000000004ff2 R12: ffff88002cf9ff80
[ 28.644776] R13: 0000000000000011 R14: 00000000000050fa R15: 00000000000054a2
[ 28.644776] FS: 00007f27db007700(0000) GS:ffff88002fc00000(0000) knlGS:0000000000000000
[ 28.644776] CS: 0010 DS: 0000 ES: 0000 CR0: 000000008005003b
[ 28.644776] CR2: 00007f8176cedcfc CR3: 000000002cd14000 CR4: 00000000000006b0
[ 28.644776] Stack:
[ 28.644776] 0000000000000046 ffffffff00000014 0000000000000001 ffffffff00000022
[ 28.644776] ffff88002cdaf300 ffff88002d72aaf0 0000000000000000 0000000000004ff2
[ 28.644776] 0000000000000014 ffffffff818104c0 ffffffff81810bc8 ffffffffffffffbe
[ 28.644776] Call Trace:
[ 28.644776] <IRQ>
[ 28.644776] [<ffffffff8125e742>] ? number.isra.1+0x302/0x330
[ 28.644776] [<ffffffff8142f35e>] tcp_gso_segment+0x11e/0x3f0
[ 28.644776] [<ffffffff8143f2c9>] inet_gso_segment+0x129/0x350
[ 28.644776] [<ffffffff810832cf>] ? __lock_acquire+0x2ef/0x1ca0
[ 28.644776] [<ffffffff813bcd9d>] skb_mac_gso_segment+0xdd/0x1e0
[ 28.644776] [<ffffffff813bcd07>] ? skb_mac_gso_segment+0x47/0x1e0
[ 28.644776] [<ffffffff813bcf00>] __skb_gso_segment+0x60/0xc0
[ 28.644776] [<ffffffff813bd203>] dev_hard_start_xmit+0x183/0x5b0
[ 28.644776] [<ffffffff813e064e>] sch_direct_xmit+0xfe/0x280
[ 28.644776] [<ffffffff813bd843>] __dev_queue_xmit+0x213/0x6b0
[ 28.644776] [<ffffffff813bd635>] ? __dev_queue_xmit+0x5/0x6b0
[ 28.644776] [<ffffffff813bdcf0>] dev_queue_xmit+0x10/0x20
[ 28.644776] [<ffffffff8140c2a9>] ip_finish_output+0x419/0x600
[ 28.644776] [<ffffffff8140c4de>] ? ip_output+0x4e/0xc0
[ 28.644776] [<ffffffff810803e4>] ? __lock_is_held+0x54/0x80
[ 28.644776] [<ffffffff8140c4de>] ip_output+0x4e/0xc0
[ 28.644776] [<ffffffff81407ffb>] ip_forward+0x21b/0x650
Eric, any chance you know wheter mucking with gso_size in this way
is supposed to work?
I will go through skb_segment and see if I can find out what exactly causes this
BUG_ON to trigger.
^ permalink raw reply
* Re: [PATCH] USB2NET : SR9800 : One chip USB2.0 USB2NET SR9800 Device Driver Support
From: Joe Perches @ 2014-01-28 8:59 UTC (permalink / raw)
To: liujunliang_ljl
Cc: davem, horms, romieu, gregkh, netdev, linux-usb, linux-kernel,
sunhecheng
In-Reply-To: <1390898200-9925-1-git-send-email-liujunliang_ljl@163.com>
On Tue, 2014-01-28 at 16:36 +0800, liujunliang_ljl@163.com wrote:
> From: Liu Junliang <liujunliang_ljl@163.com>
trivial comments...
> diff --git a/drivers/net/usb/sr9800.c b/drivers/net/usb/sr9800.c
[]
> +static int sr_rx_fixup(struct usbnet *dev, struct sk_buff *skb)
> +{
[]
> + if (size != ((~header >> 16) & 0x07ff)) {
> + netdev_err(dev->net,
> + "sr_rx_fixup() Bad Header Length\n");
printks with embedded functions names are
generally better using "%s: ", __func__
netdev_err(dev->net, "%s: Bad header length\n",
__func__);
[]
> + netdev_err(dev->net,
> + "sr_rx_fixup() Bad RX Length %d\n", size);
etc.
> + if (skb->len != offset) {
> + netdev_err(dev->net, "sr_rx_fixup() Bad SKB Length %d\n",
> + skb->len);
etc.
[]
> +static inline int sr9800_set_default_mode(struct usbnet *dev)
> +{
rather a big function to inline
[]
> + if (ret < 0) {
> + netdev_dbg(dev->net, "Write IPG,IPG1,IPG2 failed: %d", ret);
missing newline terminations
> + netdev_dbg(dev->net, "RX_CTL is 0x%04x after all initializations",
> + rx_ctl);
etc...
^ permalink raw reply
* Re: [PATCH 2/2] net: ip, ipv6: handle gso skbs in forwarding path
From: Florian Westphal @ 2014-01-28 9:12 UTC (permalink / raw)
To: Eric Dumazet, Florian Westphal, netdev
In-Reply-To: <20140128002707.GA12308@order.stressinduktion.org>
Hannes Frederic Sowa <hannes@stressinduktion.org> wrote:
> On Mon, Jan 27, 2014 at 10:22:47AM -0800, Eric Dumazet wrote:
> > On Mon, 2014-01-27 at 09:22 +0100, Florian Westphal wrote:
> >
> > > +/* called if GSO skb needs to be fragmented on forward. */
> > > +static int ip_forward_finish_gso(struct sk_buff *skb)
> > > +{
> > > + netdev_features_t features = netif_skb_features(skb);
>
> netif_skb_features uses skb->dev for determination of offloading features but
> we actually need rt->dst.dev, no?
good catch, cannot use netif_skb_features as skb->dev still
points to incoming device here...
^ permalink raw reply
* Incorrect skb->truesize calculations in net/usb/ax88179_178a.c
From: David Laight @ 2014-01-28 9:14 UTC (permalink / raw)
To: netdev@vger.kernel.org
The ax88179_178a driver contains this code for processing receive traffic:
1130 while (pkt_cnt--) {
...
1144 if (pkt_cnt == 0) {
1145 /* Skip IP alignment psudo header */
1146 skb_pull(skb, 2);
1147 skb->len = pkt_len;
1148 skb_set_tail_pointer(skb, pkt_len);
1149 skb->truesize = pkt_len + sizeof(struct sk_buff);
1150 ax88179_rx_checksum(skb, pkt_hdr);
1151 return 1;
1152 }
1153
1154 ax_skb = skb_clone(skb, GFP_ATOMIC);
1155 if (ax_skb) {
1156 ax_skb->len = pkt_len;
1157 ax_skb->data = skb->data + 2;
1158 skb_set_tail_pointer(ax_skb, pkt_len);
1159 ax_skb->truesize = pkt_len + sizeof(struct sk_buff);
1160 ax88179_rx_checksum(ax_skb, pkt_hdr);
1161 usbnet_skb_return(dev, ax_skb);
1162 } else {
1163 return 0;
1164 }
The usb receives are done with 20kB skb.
The loop above implies that they can be filled with multiple ethernet frames.
The hardware supports TSO, I don't know if it also supports receive offload.
I'm not sure what skb->trusize should be for a cloned skb (in order to get
sensible accounting). But is a single ethernet frame is received I thought
the truesize should still be 20k+, not reset to the data size.
This driver would be much better off providing single 4k buffers to the
usb stack, and then generating skb referring to the data - especially
if it does merge receives.
I'm not sure of the best way to handle the splitting of multiple ethernet
frames from shared pages, but I'm pretty sure it isn't the above.
David
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox