* [PATCH] ipv4: raw: fix icmp_filter()
From: Eric Dumazet @ 2012-09-22 10:08 UTC (permalink / raw)
To: David Miller; +Cc: netdev
From: Eric Dumazet <edumazet@google.com>
icmp_filter() should not modify its input, or else its caller
would need to recompute ip_hdr() if skb->head is reallocated.
Use skb_header_pointer() instead of pskb_may_pull() and
change the prototype to make clear both sk and skb are const.
Signed-off-by: Eric Dumazet <edumazet@google.com>
---
This is a minimal fix, to meet stable expectations.
net/ipv4/raw.c | 14 ++++++++------
1 file changed, 8 insertions(+), 6 deletions(-)
diff --git a/net/ipv4/raw.c b/net/ipv4/raw.c
index ff0f071..d23c657 100644
--- a/net/ipv4/raw.c
+++ b/net/ipv4/raw.c
@@ -131,18 +131,20 @@ found:
* 0 - deliver
* 1 - block
*/
-static __inline__ int icmp_filter(struct sock *sk, struct sk_buff *skb)
+static int icmp_filter(const struct sock *sk, const struct sk_buff *skb)
{
- int type;
+ struct icmphdr _hdr;
+ const struct icmphdr *hdr;
- if (!pskb_may_pull(skb, sizeof(struct icmphdr)))
+ hdr = skb_header_pointer(skb, skb_transport_offset(skb),
+ sizeof(_hdr), &_hdr);
+ if (!hdr)
return 1;
- type = icmp_hdr(skb)->type;
- if (type < 32) {
+ if (hdr->type < 32) {
__u32 data = raw_sk(sk)->filter.data;
- return ((1 << type) & data) != 0;
+ return ((1U << hdr->type) & data) != 0;
}
/* Do not block unknown ICMP types */
^ permalink raw reply related
* [PATCH] pppoe: drop PPPOX_ZOMBIEs in pppoe_release
From: Xiaodong Xu @ 2012-09-22 10:09 UTC (permalink / raw)
To: linux-kernel; +Cc: netdev
From: Xiaodong Xu <stid.smth@gmail.com>
When PPPOE is running over a virtual ethernet interface (e.g., a
bonding interface) and the user tries to delete the interface in case
the PPPOE state is ZOMBIE, the kernel will loop forever while
unregistering net_device for the reference count is not decreased to
zero which should have been done with dev_put().
Signed-off-by: Xiaodong Xu <stid.smth@gmail.com>
---
--- linux/drivers/net/ppp/pppoe.c.orig 2012-09-19 11:49:27.921826868 +0800
+++ linux/drivers/net/ppp/pppoe.c 2012-09-22 17:44:03.642730082 +0800
@@ -570,7 +570,7 @@ static int pppoe_release(struct socket *
po = pppox_sk(sk);
- if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND)) {
+ if (sk->sk_state & (PPPOX_CONNECTED | PPPOX_BOUND | PPPOX_ZOMBIE)) {
dev_put(po->pppoe_dev);
po->pppoe_dev = NULL;
}
--
Regards,
Xiaodong Xu
^ permalink raw reply
* [net-next 0/7][pull request] Intel Wired LAN Driver Updates
From: Jeff Kirsher @ 2012-09-22 10:30 UTC (permalink / raw)
To: davem; +Cc: Jeff Kirsher, netdev, gospo, sassmann
This series contains updates to igb only.
The following are changes since commit abb17e6c0c7b27693201dc85f75dbb184279fd10:
netlink: use <linux/export.h> instead of <linux/module.h>
and are available in the git repository at:
git://git.kernel.org/pub/scm/linux/kernel/git/jkirsher/net-next master
Alexander Duyck (5):
igb: Remove logic that was doing NUMA pseudo-aware allocations
igb: Change Tx cleanup loop to do/while instead of for
igb: Change how we populate the RSS indirection table
igb: Simplify how we populate the RSS key
igb: Use dma_unmap_addr and dma_unmap_len defines
Carolyn Wyborny (1):
igb: Fix stats output on i210/i211 parts.
Stefan Assmann (1):
igb: Change how we check for pre-existing and assigned VFs
drivers/net/ethernet/intel/igb/igb.h | 8 +-
drivers/net/ethernet/intel/igb/igb_main.c | 370 ++++++++++--------------------
2 files changed, 122 insertions(+), 256 deletions(-)
--
1.7.11.4
^ permalink raw reply
* [net-next 1/7] igb: Change how we check for pre-existing and assigned VFs
From: Jeff Kirsher @ 2012-09-22 10:30 UTC (permalink / raw)
To: davem; +Cc: Stefan Assmann, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1348309836-7107-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Stefan Assmann <sassmann@kpanic.de>
Adapt the pre-existing and assigned VFs code to the ixgbe way introduced
in commit 9297127b9cdd8d30c829ef5fd28b7cc0323a7bcd.
Instead of searching the enabled VFs we use pci_num_vf to determine enabled VFs.
By comparing to which PF an assigned VF is owned it's possible to decide
whether to leave it enabled or not.
Signed-off-by: Stefan Assmann <sassmann@kpanic.de>
Acked-by: Greg Rose <gregory.v.rose@intel.com>
Tested-by: Robert Garrett <robertx.e.garrett@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb.h | 1 -
drivers/net/ethernet/intel/igb/igb_main.c | 104 +++++++-----------------------
2 files changed, 22 insertions(+), 83 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 43c8e29..6f17f69 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -101,7 +101,6 @@ struct vf_data_storage {
u16 pf_vlan; /* When set, guest VLAN config not allowed. */
u16 pf_qos;
u16 tx_rate;
- struct pci_dev *vfdev;
};
#define IGB_VF_FLAG_CTS 0x00000001 /* VF is clear to send data */
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 246646b..0730096 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -172,8 +172,7 @@ static void igb_check_vf_rate_limit(struct igb_adapter *);
#ifdef CONFIG_PCI_IOV
static int igb_vf_configure(struct igb_adapter *adapter, int vf);
-static int igb_find_enabled_vfs(struct igb_adapter *adapter);
-static int igb_check_vf_assignment(struct igb_adapter *adapter);
+static bool igb_vfs_are_assigned(struct igb_adapter *adapter);
#endif
#ifdef CONFIG_PM
@@ -2300,11 +2299,11 @@ static void __devexit igb_remove(struct pci_dev *pdev)
/* reclaim resources allocated to VFs */
if (adapter->vf_data) {
/* disable iov and allow time for transactions to clear */
- if (!igb_check_vf_assignment(adapter)) {
+ if (igb_vfs_are_assigned(adapter)) {
+ dev_info(&pdev->dev, "Unloading driver while VFs are assigned - VFs will not be deallocated\n");
+ } else {
pci_disable_sriov(pdev);
msleep(500);
- } else {
- dev_info(&pdev->dev, "VF(s) assigned to guests!\n");
}
kfree(adapter->vf_data);
@@ -2344,7 +2343,7 @@ static void __devinit igb_probe_vfs(struct igb_adapter * adapter)
#ifdef CONFIG_PCI_IOV
struct pci_dev *pdev = adapter->pdev;
struct e1000_hw *hw = &adapter->hw;
- int old_vfs = igb_find_enabled_vfs(adapter);
+ int old_vfs = pci_num_vf(adapter->pdev);
int i;
/* Virtualization features not supported on i210 family. */
@@ -5037,102 +5036,43 @@ static int igb_notify_dca(struct notifier_block *nb, unsigned long event,
static int igb_vf_configure(struct igb_adapter *adapter, int vf)
{
unsigned char mac_addr[ETH_ALEN];
- struct pci_dev *pdev = adapter->pdev;
- struct e1000_hw *hw = &adapter->hw;
- struct pci_dev *pvfdev;
- unsigned int device_id;
- u16 thisvf_devfn;
eth_random_addr(mac_addr);
igb_set_vf_mac(adapter, vf, mac_addr);
- switch (adapter->hw.mac.type) {
- case e1000_82576:
- device_id = IGB_82576_VF_DEV_ID;
- /* VF Stride for 82576 is 2 */
- thisvf_devfn = (pdev->devfn + 0x80 + (vf << 1)) |
- (pdev->devfn & 1);
- break;
- case e1000_i350:
- device_id = IGB_I350_VF_DEV_ID;
- /* VF Stride for I350 is 4 */
- thisvf_devfn = (pdev->devfn + 0x80 + (vf << 2)) |
- (pdev->devfn & 3);
- break;
- default:
- device_id = 0;
- thisvf_devfn = 0;
- break;
- }
-
- pvfdev = pci_get_device(hw->vendor_id, device_id, NULL);
- while (pvfdev) {
- if (pvfdev->devfn == thisvf_devfn)
- break;
- pvfdev = pci_get_device(hw->vendor_id,
- device_id, pvfdev);
- }
-
- if (pvfdev)
- adapter->vf_data[vf].vfdev = pvfdev;
- else
- dev_err(&pdev->dev,
- "Couldn't find pci dev ptr for VF %4.4x\n",
- thisvf_devfn);
- return pvfdev != NULL;
+ return 0;
}
-static int igb_find_enabled_vfs(struct igb_adapter *adapter)
+static bool igb_vfs_are_assigned(struct igb_adapter *adapter)
{
- struct e1000_hw *hw = &adapter->hw;
struct pci_dev *pdev = adapter->pdev;
- struct pci_dev *pvfdev;
- u16 vf_devfn = 0;
- u16 vf_stride;
- unsigned int device_id;
- int vfs_found = 0;
+ struct pci_dev *vfdev;
+ int dev_id;
switch (adapter->hw.mac.type) {
case e1000_82576:
- device_id = IGB_82576_VF_DEV_ID;
- /* VF Stride for 82576 is 2 */
- vf_stride = 2;
+ dev_id = IGB_82576_VF_DEV_ID;
break;
case e1000_i350:
- device_id = IGB_I350_VF_DEV_ID;
- /* VF Stride for I350 is 4 */
- vf_stride = 4;
+ dev_id = IGB_I350_VF_DEV_ID;
break;
default:
- device_id = 0;
- vf_stride = 0;
- break;
- }
-
- vf_devfn = pdev->devfn + 0x80;
- pvfdev = pci_get_device(hw->vendor_id, device_id, NULL);
- while (pvfdev) {
- if (pvfdev->devfn == vf_devfn &&
- (pvfdev->bus->number >= pdev->bus->number))
- vfs_found++;
- vf_devfn += vf_stride;
- pvfdev = pci_get_device(hw->vendor_id,
- device_id, pvfdev);
+ return false;
}
- return vfs_found;
-}
-
-static int igb_check_vf_assignment(struct igb_adapter *adapter)
-{
- int i;
- for (i = 0; i < adapter->vfs_allocated_count; i++) {
- if (adapter->vf_data[i].vfdev) {
- if (adapter->vf_data[i].vfdev->dev_flags &
- PCI_DEV_FLAGS_ASSIGNED)
+ /* loop through all the VFs to see if we own any that are assigned */
+ vfdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, NULL);
+ while (vfdev) {
+ /* if we don't own it we don't care */
+ if (vfdev->is_virtfn && vfdev->physfn == pdev) {
+ /* if it is assigned we cannot release it */
+ if (vfdev->dev_flags & PCI_DEV_FLAGS_ASSIGNED)
return true;
}
+
+ vfdev = pci_get_device(PCI_VENDOR_ID_INTEL, dev_id, vfdev);
}
+
return false;
}
--
1.7.11.4
^ permalink raw reply related
* [net-next 2/7] igb: Fix stats output on i210/i211 parts.
From: Jeff Kirsher @ 2012-09-22 10:30 UTC (permalink / raw)
To: davem; +Cc: Carolyn Wyborny, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1348309836-7107-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Carolyn Wyborny <carolyn.wyborny@intel.com>
Due to a hardware issue, on i210 and i211 parts, the TNCRS statistic
provides an invalid value. This patch changes the update stats function
to increment the stat only for non-i210/i211 parts.
Signed-off-by: Carolyn Wyborny <carolyn.wyborny@intel.com>
Tested-by: Jeff Pieper <jeffrey.e.pieper@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb_main.c | 6 +++++-
1 file changed, 5 insertions(+), 1 deletion(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 0730096..60cf3eb 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -4776,7 +4776,11 @@ void igb_update_stats(struct igb_adapter *adapter,
reg = rd32(E1000_CTRL_EXT);
if (!(reg & E1000_CTRL_EXT_LINK_MODE_MASK)) {
adapter->stats.rxerrc += rd32(E1000_RXERRC);
- adapter->stats.tncrs += rd32(E1000_TNCRS);
+
+ /* this stat has invalid values on i210/i211 */
+ if ((hw->mac.type != e1000_i210) &&
+ (hw->mac.type != e1000_i211))
+ adapter->stats.tncrs += rd32(E1000_TNCRS);
}
adapter->stats.tsctc += rd32(E1000_TSCTC);
--
1.7.11.4
^ permalink raw reply related
* [net-next 3/7] igb: Remove logic that was doing NUMA pseudo-aware allocations
From: Jeff Kirsher @ 2012-09-22 10:30 UTC (permalink / raw)
To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1348309836-7107-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Alexander Duyck <alexander.h.duyck@intel.com>
This change removes the code that was doing the NUMA allocations for the
q_vectors, rings, and ring resources. The problem is the logic used assumed
that the NUMA nodes were always interleved and that is not always the case.
At some point I hope to add this functionality back in a more controlled
manner in the future.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb.h | 3 -
drivers/net/ethernet/intel/igb/igb_main.c | 95 +++++--------------------------
2 files changed, 13 insertions(+), 85 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 6f17f69..9cad058 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -213,7 +213,6 @@ struct igb_q_vector {
struct igb_ring_container rx, tx;
struct napi_struct napi;
- int numa_node;
u16 itr_val;
u8 set_itr;
@@ -258,7 +257,6 @@ struct igb_ring {
};
/* Items past this point are only used during ring alloc / free */
dma_addr_t dma; /* phys address of the ring */
- int numa_node; /* node to alloc ring memory on */
};
enum e1000_ring_flags_t {
@@ -373,7 +371,6 @@ struct igb_adapter {
int vf_rate_link_speed;
u32 rss_queues;
u32 wvbr;
- int node;
u32 *shadow_vfta;
#ifdef CONFIG_IGB_PTP
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 60cf3eb..c9997d8 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -682,52 +682,29 @@ static int igb_alloc_queues(struct igb_adapter *adapter)
{
struct igb_ring *ring;
int i;
- int orig_node = adapter->node;
for (i = 0; i < adapter->num_tx_queues; i++) {
- if (orig_node == -1) {
- int cur_node = next_online_node(adapter->node);
- if (cur_node == MAX_NUMNODES)
- cur_node = first_online_node;
- adapter->node = cur_node;
- }
- ring = kzalloc_node(sizeof(struct igb_ring), GFP_KERNEL,
- adapter->node);
- if (!ring)
- ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
+ ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
if (!ring)
goto err;
ring->count = adapter->tx_ring_count;
ring->queue_index = i;
ring->dev = &adapter->pdev->dev;
ring->netdev = adapter->netdev;
- ring->numa_node = adapter->node;
/* For 82575, context index must be unique per ring. */
if (adapter->hw.mac.type == e1000_82575)
set_bit(IGB_RING_FLAG_TX_CTX_IDX, &ring->flags);
adapter->tx_ring[i] = ring;
}
- /* Restore the adapter's original node */
- adapter->node = orig_node;
for (i = 0; i < adapter->num_rx_queues; i++) {
- if (orig_node == -1) {
- int cur_node = next_online_node(adapter->node);
- if (cur_node == MAX_NUMNODES)
- cur_node = first_online_node;
- adapter->node = cur_node;
- }
- ring = kzalloc_node(sizeof(struct igb_ring), GFP_KERNEL,
- adapter->node);
- if (!ring)
- ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
+ ring = kzalloc(sizeof(struct igb_ring), GFP_KERNEL);
if (!ring)
goto err;
ring->count = adapter->rx_ring_count;
ring->queue_index = i;
ring->dev = &adapter->pdev->dev;
ring->netdev = adapter->netdev;
- ring->numa_node = adapter->node;
/* set flag indicating ring supports SCTP checksum offload */
if (adapter->hw.mac.type >= e1000_82576)
set_bit(IGB_RING_FLAG_RX_SCTP_CSUM, &ring->flags);
@@ -741,16 +718,12 @@ static int igb_alloc_queues(struct igb_adapter *adapter)
adapter->rx_ring[i] = ring;
}
- /* Restore the adapter's original node */
- adapter->node = orig_node;
igb_cache_ring_register(adapter);
return 0;
err:
- /* Restore the adapter's original node */
- adapter->node = orig_node;
igb_free_queues(adapter);
return -ENOMEM;
@@ -1116,24 +1089,10 @@ static int igb_alloc_q_vectors(struct igb_adapter *adapter)
struct igb_q_vector *q_vector;
struct e1000_hw *hw = &adapter->hw;
int v_idx;
- int orig_node = adapter->node;
for (v_idx = 0; v_idx < adapter->num_q_vectors; v_idx++) {
- if ((adapter->num_q_vectors == (adapter->num_rx_queues +
- adapter->num_tx_queues)) &&
- (adapter->num_rx_queues == v_idx))
- adapter->node = orig_node;
- if (orig_node == -1) {
- int cur_node = next_online_node(adapter->node);
- if (cur_node == MAX_NUMNODES)
- cur_node = first_online_node;
- adapter->node = cur_node;
- }
- q_vector = kzalloc_node(sizeof(struct igb_q_vector), GFP_KERNEL,
- adapter->node);
- if (!q_vector)
- q_vector = kzalloc(sizeof(struct igb_q_vector),
- GFP_KERNEL);
+ q_vector = kzalloc(sizeof(struct igb_q_vector),
+ GFP_KERNEL);
if (!q_vector)
goto err_out;
q_vector->adapter = adapter;
@@ -1142,14 +1101,10 @@ static int igb_alloc_q_vectors(struct igb_adapter *adapter)
netif_napi_add(adapter->netdev, &q_vector->napi, igb_poll, 64);
adapter->q_vector[v_idx] = q_vector;
}
- /* Restore the adapter's original node */
- adapter->node = orig_node;
return 0;
err_out:
- /* Restore the adapter's original node */
- adapter->node = orig_node;
igb_free_q_vectors(adapter);
return -ENOMEM;
}
@@ -2423,8 +2378,6 @@ static int __devinit igb_sw_init(struct igb_adapter *adapter)
VLAN_HLEN;
adapter->min_frame_size = ETH_ZLEN + ETH_FCS_LEN;
- adapter->node = -1;
-
spin_lock_init(&adapter->stats64_lock);
#ifdef CONFIG_PCI_IOV
switch (hw->mac.type) {
@@ -2671,13 +2624,11 @@ static int igb_close(struct net_device *netdev)
int igb_setup_tx_resources(struct igb_ring *tx_ring)
{
struct device *dev = tx_ring->dev;
- int orig_node = dev_to_node(dev);
int size;
size = sizeof(struct igb_tx_buffer) * tx_ring->count;
- tx_ring->tx_buffer_info = vzalloc_node(size, tx_ring->numa_node);
- if (!tx_ring->tx_buffer_info)
- tx_ring->tx_buffer_info = vzalloc(size);
+
+ tx_ring->tx_buffer_info = vzalloc(size);
if (!tx_ring->tx_buffer_info)
goto err;
@@ -2685,18 +2636,10 @@ int igb_setup_tx_resources(struct igb_ring *tx_ring)
tx_ring->size = tx_ring->count * sizeof(union e1000_adv_tx_desc);
tx_ring->size = ALIGN(tx_ring->size, 4096);
- set_dev_node(dev, tx_ring->numa_node);
tx_ring->desc = dma_alloc_coherent(dev,
tx_ring->size,
&tx_ring->dma,
GFP_KERNEL);
- set_dev_node(dev, orig_node);
- if (!tx_ring->desc)
- tx_ring->desc = dma_alloc_coherent(dev,
- tx_ring->size,
- &tx_ring->dma,
- GFP_KERNEL);
-
if (!tx_ring->desc)
goto err;
@@ -2707,8 +2650,8 @@ int igb_setup_tx_resources(struct igb_ring *tx_ring)
err:
vfree(tx_ring->tx_buffer_info);
- dev_err(dev,
- "Unable to allocate memory for the transmit descriptor ring\n");
+ tx_ring->tx_buffer_info = NULL;
+ dev_err(dev, "Unable to allocate memory for the Tx descriptor ring\n");
return -ENOMEM;
}
@@ -2825,34 +2768,23 @@ static void igb_configure_tx(struct igb_adapter *adapter)
int igb_setup_rx_resources(struct igb_ring *rx_ring)
{
struct device *dev = rx_ring->dev;
- int orig_node = dev_to_node(dev);
- int size, desc_len;
+ int size;
size = sizeof(struct igb_rx_buffer) * rx_ring->count;
- rx_ring->rx_buffer_info = vzalloc_node(size, rx_ring->numa_node);
- if (!rx_ring->rx_buffer_info)
- rx_ring->rx_buffer_info = vzalloc(size);
+
+ rx_ring->rx_buffer_info = vzalloc(size);
if (!rx_ring->rx_buffer_info)
goto err;
- desc_len = sizeof(union e1000_adv_rx_desc);
/* Round up to nearest 4K */
- rx_ring->size = rx_ring->count * desc_len;
+ rx_ring->size = rx_ring->count * sizeof(union e1000_adv_rx_desc);
rx_ring->size = ALIGN(rx_ring->size, 4096);
- set_dev_node(dev, rx_ring->numa_node);
rx_ring->desc = dma_alloc_coherent(dev,
rx_ring->size,
&rx_ring->dma,
GFP_KERNEL);
- set_dev_node(dev, orig_node);
- if (!rx_ring->desc)
- rx_ring->desc = dma_alloc_coherent(dev,
- rx_ring->size,
- &rx_ring->dma,
- GFP_KERNEL);
-
if (!rx_ring->desc)
goto err;
@@ -2864,8 +2796,7 @@ int igb_setup_rx_resources(struct igb_ring *rx_ring)
err:
vfree(rx_ring->rx_buffer_info);
rx_ring->rx_buffer_info = NULL;
- dev_err(dev, "Unable to allocate memory for the receive descriptor"
- " ring\n");
+ dev_err(dev, "Unable to allocate memory for the Rx descriptor ring\n");
return -ENOMEM;
}
--
1.7.11.4
^ permalink raw reply related
* [net-next 4/7] igb: Change Tx cleanup loop to do/while instead of for
From: Jeff Kirsher @ 2012-09-22 10:30 UTC (permalink / raw)
To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1348309836-7107-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Alexander Duyck <alexander.h.duyck@intel.com>
This change makes it so that Tx cleanup is done in a do/while loop instead
of a for loop. The main motivation behind this is the fact that we should
never be invoked with a budget less than 1 so we can skip checking the
budget before processing the first descriptor.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb_main.c | 28 ++++++++++++++++------------
1 file changed, 16 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index c9997d8..91f542c 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -5690,7 +5690,7 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
struct igb_adapter *adapter = q_vector->adapter;
struct igb_ring *tx_ring = q_vector->tx.ring;
struct igb_tx_buffer *tx_buffer;
- union e1000_adv_tx_desc *tx_desc, *eop_desc;
+ union e1000_adv_tx_desc *tx_desc;
unsigned int total_bytes = 0, total_packets = 0;
unsigned int budget = q_vector->tx.work_limit;
unsigned int i = tx_ring->next_to_clean;
@@ -5702,16 +5702,16 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
tx_desc = IGB_TX_DESC(tx_ring, i);
i -= tx_ring->count;
- for (; budget; budget--) {
- eop_desc = tx_buffer->next_to_watch;
-
- /* prevent any other reads prior to eop_desc */
- rmb();
+ do {
+ union e1000_adv_tx_desc *eop_desc = tx_buffer->next_to_watch;
/* if next_to_watch is not set then there is no work pending */
if (!eop_desc)
break;
+ /* prevent any other reads prior to eop_desc */
+ rmb();
+
/* if DD is not set pending work has not been completed */
if (!(eop_desc->wb.status & cpu_to_le32(E1000_TXD_STAT_DD)))
break;
@@ -5767,7 +5767,13 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
tx_buffer = tx_ring->tx_buffer_info;
tx_desc = IGB_TX_DESC(tx_ring, 0);
}
- }
+
+ /* issue prefetch for next Tx descriptor */
+ prefetch(tx_desc);
+
+ /* update budget accounting */
+ budget--;
+ } while (likely(budget));
netdev_tx_completed_queue(txring_txq(tx_ring),
total_packets, total_bytes);
@@ -5783,12 +5789,10 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
if (test_bit(IGB_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags)) {
struct e1000_hw *hw = &adapter->hw;
- eop_desc = tx_buffer->next_to_watch;
-
/* Detect a transmit hang in hardware, this serializes the
* check with the clearing of time_stamp and movement of i */
clear_bit(IGB_RING_FLAG_TX_DETECT_HANG, &tx_ring->flags);
- if (eop_desc &&
+ if (tx_buffer->next_to_watch &&
time_after(jiffies, tx_buffer->time_stamp +
(adapter->tx_timeout_factor * HZ)) &&
!(rd32(E1000_STATUS) & E1000_STATUS_TXOFF)) {
@@ -5812,9 +5816,9 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
tx_ring->next_to_use,
tx_ring->next_to_clean,
tx_buffer->time_stamp,
- eop_desc,
+ tx_buffer->next_to_watch,
jiffies,
- eop_desc->wb.status);
+ tx_buffer->next_to_watch->wb.status);
netif_stop_subqueue(tx_ring->netdev,
tx_ring->queue_index);
--
1.7.11.4
^ permalink raw reply related
* [net-next 5/7] igb: Change how we populate the RSS indirection table
From: Jeff Kirsher @ 2012-09-22 10:30 UTC (permalink / raw)
To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1348309836-7107-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Alexander Duyck <alexander.h.duyck@intel.com>
This patch cleans up our RSS indirection table configuration so that we
generate the same table regardless of CPU endianness. In addition it
changes the table setup so that instead of doing a modulo based setup it is
instead a divisor based setup. The advantage to this is that we should be
able to take the Rx hash and compute the Rx queue with very little CPU
overhead if needed.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb_main.c | 55 +++++++++++++++----------------
1 file changed, 26 insertions(+), 29 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 91f542c..27688d9 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2834,11 +2834,7 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
u32 mrqc, rxcsum;
- u32 j, num_rx_queues, shift = 0, shift2 = 0;
- union e1000_reta {
- u32 dword;
- u8 bytes[4];
- } reta;
+ u32 j, num_rx_queues, shift = 0;
static const u8 rsshash[40] = {
0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 0x41, 0x67,
0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 0xd0, 0xca, 0x2b, 0xcb,
@@ -2856,35 +2852,36 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
num_rx_queues = adapter->rss_queues;
- if (adapter->vfs_allocated_count) {
- /* 82575 and 82576 supports 2 RSS queues for VMDq */
- switch (hw->mac.type) {
- case e1000_i350:
- case e1000_82580:
- num_rx_queues = 1;
- shift = 0;
- break;
- case e1000_82576:
+ switch (hw->mac.type) {
+ case e1000_82575:
+ shift = 6;
+ break;
+ case e1000_82576:
+ /* 82576 supports 2 RSS queues for SR-IOV */
+ if (adapter->vfs_allocated_count) {
shift = 3;
num_rx_queues = 2;
- break;
- case e1000_82575:
- shift = 2;
- shift2 = 6;
- default:
- break;
}
- } else {
- if (hw->mac.type == e1000_82575)
- shift = 6;
+ break;
+ default:
+ break;
}
- for (j = 0; j < (32 * 4); j++) {
- reta.bytes[j & 3] = (j % num_rx_queues) << shift;
- if (shift2)
- reta.bytes[j & 3] |= num_rx_queues << shift2;
- if ((j & 3) == 3)
- wr32(E1000_RETA(j >> 2), reta.dword);
+ /*
+ * Populate the indirection table 4 entries at a time. To do this
+ * we are generating the results for n and n+2 and then interleaving
+ * those with the results with n+1 and n+3.
+ */
+ for (j = 0; j < 32; j++) {
+ /* first pass generates n and n+2 */
+ u32 base = ((j * 0x00040004) + 0x00020000) * num_rx_queues;
+ u32 reta = (base & 0x07800780) >> (7 - shift);
+
+ /* second pass generates n+1 and n+3 */
+ base += 0x00010001 * num_rx_queues;
+ reta |= (base & 0x07800780) << (1 + shift);
+
+ wr32(E1000_RETA(j), reta);
}
/*
--
1.7.11.4
^ permalink raw reply related
* [net-next 6/7] igb: Simplify how we populate the RSS key
From: Jeff Kirsher @ 2012-09-22 10:30 UTC (permalink / raw)
To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1348309836-7107-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Alexander Duyck <alexander.h.duyck@intel.com>
Instead of storing the RSS key as a character array we can simplify the
configuration by making it a u32 array. This allows us to just write one
value per register without any unnecessary operations to construct the
value.
This change will produce the same exact key, the only difference is that I
translated the u8 array to a u32 array which will be correctly ordered on
writes to hardware by the cpu_to_le32 operations that are built into the
writel calls.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb_main.c | 18 ++++++------------
1 file changed, 6 insertions(+), 12 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index 27688d9..db6e456 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -2835,20 +2835,14 @@ static void igb_setup_mrqc(struct igb_adapter *adapter)
struct e1000_hw *hw = &adapter->hw;
u32 mrqc, rxcsum;
u32 j, num_rx_queues, shift = 0;
- static const u8 rsshash[40] = {
- 0x6d, 0x5a, 0x56, 0xda, 0x25, 0x5b, 0x0e, 0xc2, 0x41, 0x67,
- 0x25, 0x3d, 0x43, 0xa3, 0x8f, 0xb0, 0xd0, 0xca, 0x2b, 0xcb,
- 0xae, 0x7b, 0x30, 0xb4, 0x77, 0xcb, 0x2d, 0xa3, 0x80, 0x30,
- 0xf2, 0x0c, 0x6a, 0x42, 0xb7, 0x3b, 0xbe, 0xac, 0x01, 0xfa };
+ static const u32 rsskey[10] = { 0xDA565A6D, 0xC20E5B25, 0x3D256741,
+ 0xB08FA343, 0xCB2BCAD0, 0xB4307BAE,
+ 0xA32DCB77, 0x0CF23080, 0x3BB7426A,
+ 0xFA01ACBE };
/* Fill out hash function seeds */
- for (j = 0; j < 10; j++) {
- u32 rsskey = rsshash[(j * 4)];
- rsskey |= rsshash[(j * 4) + 1] << 8;
- rsskey |= rsshash[(j * 4) + 2] << 16;
- rsskey |= rsshash[(j * 4) + 3] << 24;
- array_wr32(E1000_RSSRK(0), j, rsskey);
- }
+ for (j = 0; j < 10; j++)
+ wr32(E1000_RSSRK(j), rsskey[j]);
num_rx_queues = adapter->rss_queues;
--
1.7.11.4
^ permalink raw reply related
* [net-next 7/7] igb: Use dma_unmap_addr and dma_unmap_len defines
From: Jeff Kirsher @ 2012-09-22 10:30 UTC (permalink / raw)
To: davem; +Cc: Alexander Duyck, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1348309836-7107-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Alexander Duyck <alexander.h.duyck@intel.com>
This change is meant to improve performance on systems that do not require
the DMA unmap calls. On those systems we do not need to make use of the
unmap address for Tx or the unmap length so we can drop both thereby
reducing the size of the Tx buffer info structure.
In addition I have changed the logic to check for unmap length instead of
unmap address when checking to see if a buffer needs to be unmapped from
DMA use. The reasons for this change is that on some platforms it is
possible to receive a valid DMA address of 0 from an IOMMU.
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Aaron Brown <aaron.f.brown@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/igb/igb.h | 4 +-
drivers/net/ethernet/intel/igb/igb_main.c | 64 +++++++++++++++----------------
2 files changed, 34 insertions(+), 34 deletions(-)
diff --git a/drivers/net/ethernet/intel/igb/igb.h b/drivers/net/ethernet/intel/igb/igb.h
index 9cad058..8aad230 100644
--- a/drivers/net/ethernet/intel/igb/igb.h
+++ b/drivers/net/ethernet/intel/igb/igb.h
@@ -168,8 +168,8 @@ struct igb_tx_buffer {
unsigned int bytecount;
u16 gso_segs;
__be16 protocol;
- dma_addr_t dma;
- u32 length;
+ DEFINE_DMA_UNMAP_ADDR(dma);
+ DEFINE_DMA_UNMAP_LEN(len);
u32 tx_flags;
};
diff --git a/drivers/net/ethernet/intel/igb/igb_main.c b/drivers/net/ethernet/intel/igb/igb_main.c
index db6e456..60bf465 100644
--- a/drivers/net/ethernet/intel/igb/igb_main.c
+++ b/drivers/net/ethernet/intel/igb/igb_main.c
@@ -403,8 +403,8 @@ static void igb_dump(struct igb_adapter *adapter)
buffer_info = &tx_ring->tx_buffer_info[tx_ring->next_to_clean];
pr_info(" %5d %5X %5X %016llX %04X %p %016llX\n",
n, tx_ring->next_to_use, tx_ring->next_to_clean,
- (u64)buffer_info->dma,
- buffer_info->length,
+ (u64)dma_unmap_addr(buffer_info, dma),
+ dma_unmap_len(buffer_info, len),
buffer_info->next_to_watch,
(u64)buffer_info->time_stamp);
}
@@ -455,8 +455,8 @@ static void igb_dump(struct igb_adapter *adapter)
" %04X %p %016llX %p%s\n", i,
le64_to_cpu(u0->a),
le64_to_cpu(u0->b),
- (u64)buffer_info->dma,
- buffer_info->length,
+ (u64)dma_unmap_addr(buffer_info, dma),
+ dma_unmap_len(buffer_info, len),
buffer_info->next_to_watch,
(u64)buffer_info->time_stamp,
buffer_info->skb, next_desc);
@@ -465,7 +465,8 @@ static void igb_dump(struct igb_adapter *adapter)
print_hex_dump(KERN_INFO, "",
DUMP_PREFIX_ADDRESS,
16, 1, buffer_info->skb->data,
- buffer_info->length, true);
+ dma_unmap_len(buffer_info, len),
+ true);
}
}
@@ -3198,20 +3199,20 @@ void igb_unmap_and_free_tx_resource(struct igb_ring *ring,
{
if (tx_buffer->skb) {
dev_kfree_skb_any(tx_buffer->skb);
- if (tx_buffer->dma)
+ if (dma_unmap_len(tx_buffer, len))
dma_unmap_single(ring->dev,
- tx_buffer->dma,
- tx_buffer->length,
+ dma_unmap_addr(tx_buffer, dma),
+ dma_unmap_len(tx_buffer, len),
DMA_TO_DEVICE);
- } else if (tx_buffer->dma) {
+ } else if (dma_unmap_len(tx_buffer, len)) {
dma_unmap_page(ring->dev,
- tx_buffer->dma,
- tx_buffer->length,
+ dma_unmap_addr(tx_buffer, dma),
+ dma_unmap_len(tx_buffer, len),
DMA_TO_DEVICE);
}
tx_buffer->next_to_watch = NULL;
tx_buffer->skb = NULL;
- tx_buffer->dma = 0;
+ dma_unmap_len_set(tx_buffer, len, 0);
/* buffer_info must be completely set up in the transmit path */
}
@@ -4206,7 +4207,7 @@ static void igb_tx_map(struct igb_ring *tx_ring,
const u8 hdr_len)
{
struct sk_buff *skb = first->skb;
- struct igb_tx_buffer *tx_buffer_info;
+ struct igb_tx_buffer *tx_buffer;
union e1000_adv_tx_desc *tx_desc;
dma_addr_t dma;
struct skb_frag_struct *frag = &skb_shinfo(skb)->frags[0];
@@ -4227,8 +4228,8 @@ static void igb_tx_map(struct igb_ring *tx_ring,
goto dma_error;
/* record length, and DMA address */
- first->length = size;
- first->dma = dma;
+ dma_unmap_len_set(first, len, size);
+ dma_unmap_addr_set(first, dma, dma);
tx_desc->read.buffer_addr = cpu_to_le64(dma);
for (;;) {
@@ -4270,9 +4271,9 @@ static void igb_tx_map(struct igb_ring *tx_ring,
if (dma_mapping_error(tx_ring->dev, dma))
goto dma_error;
- tx_buffer_info = &tx_ring->tx_buffer_info[i];
- tx_buffer_info->length = size;
- tx_buffer_info->dma = dma;
+ tx_buffer = &tx_ring->tx_buffer_info[i];
+ dma_unmap_len_set(tx_buffer, len, size);
+ dma_unmap_addr_set(tx_buffer, dma, dma);
tx_desc->read.olinfo_status = 0;
tx_desc->read.buffer_addr = cpu_to_le64(dma);
@@ -4323,9 +4324,9 @@ dma_error:
/* clear dma mappings for failed tx_buffer_info map */
for (;;) {
- tx_buffer_info = &tx_ring->tx_buffer_info[i];
- igb_unmap_and_free_tx_resource(tx_ring, tx_buffer_info);
- if (tx_buffer_info == first)
+ tx_buffer = &tx_ring->tx_buffer_info[i];
+ igb_unmap_and_free_tx_resource(tx_ring, tx_buffer);
+ if (tx_buffer == first)
break;
if (i == 0)
i = tx_ring->count;
@@ -5716,18 +5717,19 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
/* free the skb */
dev_kfree_skb_any(tx_buffer->skb);
- tx_buffer->skb = NULL;
/* unmap skb header data */
dma_unmap_single(tx_ring->dev,
- tx_buffer->dma,
- tx_buffer->length,
+ dma_unmap_addr(tx_buffer, dma),
+ dma_unmap_len(tx_buffer, len),
DMA_TO_DEVICE);
+ /* clear tx_buffer data */
+ tx_buffer->skb = NULL;
+ dma_unmap_len_set(tx_buffer, len, 0);
+
/* clear last DMA location and unmap remaining buffers */
while (tx_desc != eop_desc) {
- tx_buffer->dma = 0;
-
tx_buffer++;
tx_desc++;
i++;
@@ -5738,17 +5740,15 @@ static bool igb_clean_tx_irq(struct igb_q_vector *q_vector)
}
/* unmap any remaining paged data */
- if (tx_buffer->dma) {
+ if (dma_unmap_len(tx_buffer, len)) {
dma_unmap_page(tx_ring->dev,
- tx_buffer->dma,
- tx_buffer->length,
+ dma_unmap_addr(tx_buffer, dma),
+ dma_unmap_len(tx_buffer, len),
DMA_TO_DEVICE);
+ dma_unmap_len_set(tx_buffer, len, 0);
}
}
- /* clear last DMA location */
- tx_buffer->dma = 0;
-
/* move us one more past the eop_desc for start of next pkt */
tx_buffer++;
tx_desc++;
--
1.7.11.4
^ permalink raw reply related
* Re: [PATCH 2/7][RFC] netfilter: add xt_qtaguid matching module
From: Eric W. Biederman @ 2012-09-22 13:38 UTC (permalink / raw)
To: John Stultz
Cc: LKML, JP Abgrall, netdev, Ashish Sharma, Peter P Waskiewicz Jr
In-Reply-To: <1348279853-44499-3-git-send-email-john.stultz@linaro.org>
I just took a quick skim through the patch, and spotted a few things.
This patch is going to need to handle current_fsuid returning a kuid_t.
The permission checks are weird, and ancient looking.
There is no network namespace handling, to the point I don't think
the code will function properly if network namespace support is enabled
in the kernel.
The code probably wants to use struct pid *pid, instead of pid_t values.
Both to cope with the pid namespace and to avoid issues with pid wrap
around.
A few more comments below.
Eric
John Stultz <john.stultz@linaro.org> writes:
> From: JP Abgrall <jpa@google.com>
>
> This module allows tracking stats at the socket level for given UIDs.
> It replaces xt_owner.
> If the --uid-owner is not specified, it will just count stats based on
> who the skb belongs to. This will even happen on incoming skbs as it
> looks into the skb via xt_socket magic to see who owns it.
> If an skb is lost, it will be assigned to uid=0.
>
> To control what sockets of what UIDs are tagged by what, one uses:
> echo t $sock_fd $accounting_tag $the_billed_uid \
> > /proc/net/xt_qtaguid/ctrl
> So whenever an skb belongs to a sock_fd, it will be accounted against
> $the_billed_uid
> and matching stats will show up under the uid with the given
> $accounting_tag.
>
> Because the number of allocations for the stats structs is not that big:
> ~500 apps * 32 per app
> we'll just do it atomic. This avoids walking lists many times, and
> the fancy worker thread handling. Slabs will grow when needed later.
>
> It use netdevice and inetaddr notifications instead of hooks in the core dev
> code to track when a device comes and goes. This removes the need for
> exposed iface_stat.h.
>
> Put procfs dirs in /proc/net/xt_qtaguid/
> ctrl
> stats
> iface_stat/<iface>/...
> The uid stats are obtainable in ./stats.
>
> Cc: netdev@vger.kernel.org
> Cc: JP Abgrall <jpa@google.com>
> Cc: Ashish Sharma <ashishsharma@google.com>
> Cc: Peter P Waskiewicz Jr <peter.p.waskiewicz.jr@intel.com>
> Signed-off-by: JP Abgrall <jpa@google.com>
> [Dropped paranoid network ifdefs and minor compile fixups -jstultz]
> Signed-off-by: John Stultz <john.stultz@linaro.org>
> ---
> +static struct qtaguid_event_counts qtu_events;
> +/*----------------------------------------------*/
> +static bool can_manipulate_uids(void)
> +{
You probably want something like a test for capable(CAP_SETUID).
Certainly raw check for the uid == 0 fell out of common practice
for this sort of thing a decade or so ago.
> + /* root pwnd */
> + return unlikely(!current_fsuid()) || unlikely(!proc_ctrl_write_gid)
> + || in_egroup_p(proc_ctrl_write_gid);
> +}
> +
> +static bool can_impersonate_uid(uid_t uid)
> +{
> + return uid == current_fsuid() || can_manipulate_uids();
> +}
> +
> +static bool can_read_other_uid_stats(uid_t uid)
> +{
Perhaps may_ptrace?
> + /* root pwnd */
> + return unlikely(!current_fsuid()) || uid == current_fsuid()
> + || unlikely(!proc_stats_readall_gid)
> + || in_egroup_p(proc_stats_readall_gid);
> +}
> +
> +/*
> + * Track tag that this socket is transferring data for, and not necessarily
> + * the uid that owns the socket.
> + * This is the tag against which tag_stat.counters will be billed.
> + * These structs need to be looked up by sock and pid.
> + */
> +struct sock_tag {
> + struct rb_node sock_node;
> + struct sock *sk; /* Only used as a number, never dereferenced */
> + /* The socket is needed for sockfd_put() */
> + struct socket *socket;
> + /* Used to associate with a given pid */
> + struct list_head list; /* in proc_qtu_data.sock_tag_list */
> + pid_t pid;
You probably want this to be "struct pid *pid;"
> +
> + tag_t tag;
> +};
> + * The qtu uid data is used to track resources that are created directly or
> + * indirectly by processes (uid tracked).
> + * It is shared by the processes with the same uid.
> + * Some of the resource will be counted to prevent further rogue allocations,
> + * some will need freeing once the owner process (uid) exits.
> + */
> +struct uid_tag_data {
> + struct rb_node node;
> + uid_t uid;
You probably want to say kuid_t uid here.
> + /*
> + * For the uid, how many accounting tags have been set.
> + */
> + int num_active_tags;
> + /* Track the number of proc_qtu_data that reference it */
> + int num_pqd;
> + struct rb_root tag_ref_tree;
> + /* No tag_node_tree_lock; use uid_tag_data_tree_lock */
> +};
> +struct proc_qtu_data {
> + struct rb_node node;
> + pid_t pid;
I suspect you want to use "struct pid *pid" here.
> +
> + struct uid_tag_data *parent_tag_data;
> +
> + /* Tracks the sock_tags that need freeing upon this proc's death */
> + struct list_head sock_tag_list;
> + /* No spinlock_t sock_tag_list_lock; use the global one. */
> +};
> +
> diff --git a/net/netfilter/xt_qtaguid.c b/net/netfilter/xt_qtaguid.c
> new file mode 100644
> index 0000000..7c4ac46
> +/*------------------------------------------*/
> +static int __init qtaguid_proc_register(struct proc_dir_entry **res_procdir)
> +{
> + int ret;
> + *res_procdir = proc_mkdir(module_procdirname, init_net.proc_net);
You probably want to handle all of the network namespaces.
> + if (!*res_procdir) {
> + pr_err("qtaguid: failed to create proc/.../xt_qtaguid\n");
> + ret = -ENOMEM;
> + goto no_dir;
> + }
> +
^ permalink raw reply
* [PATCH net-next 1/4] tcp: extract code to compute SYNACK RTT
From: Neal Cardwell @ 2012-09-22 14:18 UTC (permalink / raw)
To: David Miller
Cc: netdev, Eric Dumazet, Yuchung Cheng, Jerry Chu, Neal Cardwell
In preparation for adding another spot where we compute the SYNACK
RTT, extract this code so that it can be shared.
Signed-off-by: Neal Cardwell <ncardwell@google.com>
---
include/net/tcp.h | 9 +++++++++
net/ipv4/tcp_ipv4.c | 4 +---
net/ipv6/tcp_ipv6.c | 4 +---
3 files changed, 11 insertions(+), 6 deletions(-)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index a8cb00c..a718d0e 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1137,6 +1137,15 @@ static inline void tcp_openreq_init(struct request_sock *req,
ireq->loc_port = tcp_hdr(skb)->dest;
}
+/* Compute time elapsed between SYNACK and the ACK completing 3WHS */
+static inline void tcp_synack_rtt_meas(struct sock *sk,
+ struct request_sock *req)
+{
+ if (tcp_rsk(req)->snt_synack)
+ tcp_valid_rtt_meas(sk,
+ tcp_time_stamp - tcp_rsk(req)->snt_synack);
+}
+
extern void tcp_enter_memory_pressure(struct sock *sk);
static inline int keepalive_intvl_when(const struct tcp_sock *tp)
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index e64abed..1e66f7f 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -1733,9 +1733,7 @@ struct sock *tcp_v4_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;
tcp_initialize_rcv_mss(newsk);
- if (tcp_rsk(req)->snt_synack)
- tcp_valid_rtt_meas(newsk,
- tcp_time_stamp - tcp_rsk(req)->snt_synack);
+ tcp_synack_rtt_meas(newsk, req);
newtp->total_retrans = req->retrans;
#ifdef CONFIG_TCP_MD5SIG
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index f3bfb8b..cfeeeb7 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1348,9 +1348,7 @@ static struct sock * tcp_v6_syn_recv_sock(struct sock *sk, struct sk_buff *skb,
newtp->advmss = tcp_sk(sk)->rx_opt.user_mss;
tcp_initialize_rcv_mss(newsk);
- if (tcp_rsk(req)->snt_synack)
- tcp_valid_rtt_meas(newsk,
- tcp_time_stamp - tcp_rsk(req)->snt_synack);
+ tcp_synack_rtt_meas(newsk, req);
newtp->total_retrans = req->retrans;
newinet->inet_daddr = newinet->inet_saddr = LOOPBACK4_IPV6;
--
1.7.7.3
^ permalink raw reply related
* [PATCH net-next 2/4] tcp: TCP Fast Open Server - take SYNACK RTT after completing 3WHS
From: Neal Cardwell @ 2012-09-22 14:18 UTC (permalink / raw)
To: David Miller
Cc: netdev, Eric Dumazet, Yuchung Cheng, Jerry Chu, Neal Cardwell
In-Reply-To: <1348323537-30310-1-git-send-email-ncardwell@google.com>
When taking SYNACK RTT samples for servers using TCP Fast Open, fix
the code to ensure that we only call tcp_valid_rtt_meas() after we
receive the ACK that completes the 3-way handshake.
Previously we were always taking an RTT sample in
tcp_v4_syn_recv_sock(). However, for TCP Fast Open connections
tcp_v4_conn_req_fastopen() calls tcp_v4_syn_recv_sock() at the time we
receive the SYN. So for TFO we must wait until tcp_rcv_state_process()
to take the RTT sample.
To fix this, we wait until after TFO calls tcp_v4_syn_recv_sock()
before we set the snt_synack timestamp, since tcp_synack_rtt_meas()
already ensures that we only take a SYNACK RTT sample if snt_synack is
non-zero. To be careful, we only take a snt_synack timestamp when
a SYNACK transmit or retransmit succeeds.
Signed-off-by: Neal Cardwell <ncardwell@google.com>
---
include/net/tcp.h | 1 +
net/ipv4/tcp_input.c | 1 +
net/ipv4/tcp_ipv4.c | 12 +++++++++---
net/ipv6/tcp_ipv6.c | 2 +-
4 files changed, 12 insertions(+), 4 deletions(-)
diff --git a/include/net/tcp.h b/include/net/tcp.h
index a718d0e..6feeccd 100644
--- a/include/net/tcp.h
+++ b/include/net/tcp.h
@@ -1125,6 +1125,7 @@ static inline void tcp_openreq_init(struct request_sock *req,
req->cookie_ts = 0;
tcp_rsk(req)->rcv_isn = TCP_SKB_CB(skb)->seq;
tcp_rsk(req)->rcv_nxt = TCP_SKB_CB(skb)->seq + 1;
+ tcp_rsk(req)->snt_synack = 0;
req->mss = rx_opt->mss_clamp;
req->ts_recent = rx_opt->saw_tstamp ? rx_opt->rcv_tsval : 0;
ireq->tstamp_ok = rx_opt->tstamp_ok;
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index e2bec81..bb32668 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5983,6 +5983,7 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
* need req so release it.
*/
if (req) {
+ tcp_synack_rtt_meas(sk, req);
reqsk_fastopen_remove(sk, req, false);
} else {
/* Make sure socket is routed, for
diff --git a/net/ipv4/tcp_ipv4.c b/net/ipv4/tcp_ipv4.c
index 1e66f7f..0a7e020 100644
--- a/net/ipv4/tcp_ipv4.c
+++ b/net/ipv4/tcp_ipv4.c
@@ -868,6 +868,8 @@ static int tcp_v4_send_synack(struct sock *sk, struct dst_entry *dst,
ireq->rmt_addr,
ireq->opt);
err = net_xmit_eval(err);
+ if (!tcp_rsk(req)->snt_synack && !err)
+ tcp_rsk(req)->snt_synack = tcp_time_stamp;
}
return err;
@@ -1382,6 +1384,7 @@ static int tcp_v4_conn_req_fastopen(struct sock *sk,
struct request_sock_queue *queue = &inet_csk(sk)->icsk_accept_queue;
const struct inet_request_sock *ireq = inet_rsk(req);
struct sock *child;
+ int err;
req->retrans = 0;
req->sk = NULL;
@@ -1393,8 +1396,11 @@ static int tcp_v4_conn_req_fastopen(struct sock *sk,
kfree_skb(skb_synack);
return -1;
}
- ip_build_and_send_pkt(skb_synack, sk, ireq->loc_addr,
- ireq->rmt_addr, ireq->opt);
+ err = ip_build_and_send_pkt(skb_synack, sk, ireq->loc_addr,
+ ireq->rmt_addr, ireq->opt);
+ err = net_xmit_eval(err);
+ if (!err)
+ tcp_rsk(req)->snt_synack = tcp_time_stamp;
/* XXX (TFO) - is it ok to ignore error and continue? */
spin_lock(&queue->fastopenq->lock);
@@ -1612,7 +1618,6 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
isn = tcp_v4_init_sequence(skb);
}
tcp_rsk(req)->snt_isn = isn;
- tcp_rsk(req)->snt_synack = tcp_time_stamp;
if (dst == NULL) {
dst = inet_csk_route_req(sk, &fl4, req);
@@ -1650,6 +1655,7 @@ int tcp_v4_conn_request(struct sock *sk, struct sk_buff *skb)
if (err || want_cookie)
goto drop_and_free;
+ tcp_rsk(req)->snt_synack = tcp_time_stamp;
tcp_rsk(req)->listener = NULL;
/* Add the request_sock to the SYN table */
inet_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
diff --git a/net/ipv6/tcp_ipv6.c b/net/ipv6/tcp_ipv6.c
index cfeeeb7..d6212d6 100644
--- a/net/ipv6/tcp_ipv6.c
+++ b/net/ipv6/tcp_ipv6.c
@@ -1169,7 +1169,6 @@ static int tcp_v6_conn_request(struct sock *sk, struct sk_buff *skb)
}
have_isn:
tcp_rsk(req)->snt_isn = isn;
- tcp_rsk(req)->snt_synack = tcp_time_stamp;
if (security_inet_conn_request(sk, skb, req))
goto drop_and_release;
@@ -1180,6 +1179,7 @@ have_isn:
want_cookie)
goto drop_and_free;
+ tcp_rsk(req)->snt_synack = tcp_time_stamp;
tcp_rsk(req)->listener = NULL;
inet6_csk_reqsk_queue_hash_add(sk, req, TCP_TIMEOUT_INIT);
return 0;
--
1.7.7.3
^ permalink raw reply related
* [PATCH net-next 3/4] tcp: TCP Fast Open Server - note timestamps and retransmits for SYNACK RTT
From: Neal Cardwell @ 2012-09-22 14:18 UTC (permalink / raw)
To: David Miller
Cc: netdev, Eric Dumazet, Yuchung Cheng, Jerry Chu, Neal Cardwell
In-Reply-To: <1348323537-30310-1-git-send-email-ncardwell@google.com>
Previously, when using TCP Fast Open a server would return from
tcp_check_req() before updating snt_synack based on TCP timestamp echo
replies and whether or not we've retransmitted the SYNACK. The result
was that (a) for TFO connections using timestamps we used an incorrect
baseline SYNACK send time (tcp_time_stamp of SYNACK send instead of
rcv_tsecr), and (b) for TFO connections that do not have TCP
timestamps but retransmit the SYNACK we took a SYNACK RTT sample when
we should not take a sample.
This fix merely moves the snt_synack update logic a bit earlier in the
function, so that connections using TCP Fast Open will properly do
these updates when the ACK for the SYNACK arrives.
Moving this snt_synack update logic means that with TCP_DEFER_ACCEPT
enabled we do a few instructions of wasted work on each bare ACK, but
that seems OK.
Signed-off-by: Neal Cardwell <ncardwell@google.com>
---
net/ipv4/tcp_minisocks.c | 10 ++++++----
1 files changed, 6 insertions(+), 4 deletions(-)
diff --git a/net/ipv4/tcp_minisocks.c b/net/ipv4/tcp_minisocks.c
index 5792577..27536ba 100644
--- a/net/ipv4/tcp_minisocks.c
+++ b/net/ipv4/tcp_minisocks.c
@@ -692,6 +692,12 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
if (!(flg & TCP_FLAG_ACK))
return NULL;
+ /* Got ACK for our SYNACK, so update baseline for SYNACK RTT sample. */
+ if (tmp_opt.saw_tstamp && tmp_opt.rcv_tsecr)
+ tcp_rsk(req)->snt_synack = tmp_opt.rcv_tsecr;
+ else if (req->retrans) /* don't take RTT sample if retrans && ~TS */
+ tcp_rsk(req)->snt_synack = 0;
+
/* For Fast Open no more processing is needed (sk is the
* child socket).
*/
@@ -705,10 +711,6 @@ struct sock *tcp_check_req(struct sock *sk, struct sk_buff *skb,
NET_INC_STATS_BH(sock_net(sk), LINUX_MIB_TCPDEFERACCEPTDROP);
return NULL;
}
- if (tmp_opt.saw_tstamp && tmp_opt.rcv_tsecr)
- tcp_rsk(req)->snt_synack = tmp_opt.rcv_tsecr;
- else if (req->retrans) /* don't take RTT sample if retrans && ~TS */
- tcp_rsk(req)->snt_synack = 0;
/* OK, ACK is valid, create big socket and
* feed this segment to it. It will repeat all
--
1.7.7.3
^ permalink raw reply related
* [PATCH net-next 4/4] tcp: TCP Fast Open Server - call tcp_validate_incoming() for all packets
From: Neal Cardwell @ 2012-09-22 14:18 UTC (permalink / raw)
To: David Miller
Cc: netdev, Eric Dumazet, Yuchung Cheng, Jerry Chu, Neal Cardwell
In-Reply-To: <1348323537-30310-1-git-send-email-ncardwell@google.com>
A TCP Fast Open (TFO) passive connection must call both
tcp_check_req() and tcp_validate_incoming() for all incoming ACKs that
are attempting to complete the 3WHS.
This is needed to parallel all the action that happens for a non-TFO
connection, where for an ACK that is attempting to complete the 3WHS
we call both tcp_check_req() and tcp_validate_incoming().
For example, upon receiving the ACK that completes the 3WHS, we need
to call tcp_fast_parse_options() and update ts_recent based on the
incoming timestamp value in the ACK.
One symptom of the problem with the previous code was that for passive
TFO connections using TCP timestamps, the outgoing TS ecr values
ignored the incoming TS val value on the ACK that completed the 3WHS.
Signed-off-by: Neal Cardwell <ncardwell@google.com>
---
net/ipv4/tcp_input.c | 3 ++-
1 files changed, 2 insertions(+), 1 deletions(-)
diff --git a/net/ipv4/tcp_input.c b/net/ipv4/tcp_input.c
index bb32668..36e069a1 100644
--- a/net/ipv4/tcp_input.c
+++ b/net/ipv4/tcp_input.c
@@ -5969,7 +5969,8 @@ int tcp_rcv_state_process(struct sock *sk, struct sk_buff *skb,
if (tcp_check_req(sk, skb, req, NULL, true) == NULL)
goto discard;
- } else if (!tcp_validate_incoming(sk, skb, th, 0))
+ }
+ if (!tcp_validate_incoming(sk, skb, th, 0))
return 0;
/* step 5: check the ACK field */
--
1.7.7.3
^ permalink raw reply related
* Re: [PATCH V2 net-next 3/4] ptp: link the phc device to its parent device
From: Ben Hutchings @ 2012-09-22 15:40 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev, David Miller, Jacob Keller, Jeff Kirsher, John Stultz,
Matthew Vick
In-Reply-To: <847f89f4f5a2757c2487b23dac218e15613c2bb5.1348299094.git.richardcochran@gmail.com>
On Sat, 2012-09-22 at 09:42 +0200, Richard Cochran wrote:
> PTP Hardware Clock devices appear as class devices in sysfs. This patch
> changes the registration API to use the parent device, clarifying the
> clock's relationship to the underlying device.
[...]
> --- a/drivers/net/ethernet/sfc/ptp.c
> +++ b/drivers/net/ethernet/sfc/ptp.c
> @@ -931,7 +931,8 @@ static int efx_ptp_probe_channel(struct efx_channel *channel)
> ptp->phc_clock_info.settime = efx_phc_settime;
> ptp->phc_clock_info.enable = efx_phc_enable;
>
> - ptp->phc_clock = ptp_clock_register(&ptp->phc_clock_info);
> + ptp->phc_clock = ptp_clock_register(&ptp->phc_clock_info,
> + &channel->napi_dev->dev);
[...]
channel->napi_dev is the net device, not the PCI device. The parent
device should be &efx->pci_dev->dev.
Ben.
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH V2 net-next 4/4] ptp: clarify the clock_name sysfs attribute
From: Ben Hutchings @ 2012-09-22 15:44 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev, David Miller, Jacob Keller, Jeff Kirsher, John Stultz,
Matthew Vick
In-Reply-To: <6bc914f0607428ab0d8f5d5fc42a5e87bedc95c5.1348299094.git.richardcochran@gmail.com>
On Sat, 2012-09-22 at 09:42 +0200, Richard Cochran wrote:
> There has been some confusion among PHC driver authors about the
> intended purpose of the clock_name attribute. This patch expands the
> documation in order to clarify how the clock_name field should be
> understood.
>
> Signed-off-by: Richard Cochran <richardcochran@gmail.com>
> ---
> Documentation/ABI/testing/sysfs-ptp | 5 ++++-
> 1 files changed, 4 insertions(+), 1 deletions(-)
>
> diff --git a/Documentation/ABI/testing/sysfs-ptp b/Documentation/ABI/testing/sysfs-ptp
> index d40d2b5..c906488 100644
> --- a/Documentation/ABI/testing/sysfs-ptp
> +++ b/Documentation/ABI/testing/sysfs-ptp
> @@ -19,7 +19,10 @@ Date: September 2010
> Contact: Richard Cochran <richardcochran@gmail.com>
> Description:
> This file contains the name of the PTP hardware clock
> - as a human readable string.
> + as a human readable string. The purpose of this
> + attribute is to provide the user with a "friendly
> + name" and to help distinguish PHY based devices from
> + MAC based ones.
Might also be worth saying that it is not required to be unique. And
this explanation should also go in the kernel-doc in ptp_clock_kernel.h,
which is what driver writers are most likely to read.
Ben.
> What: /sys/class/ptp/ptpN/max_adjustment
> Date: September 2010
--
Ben Hutchings, Staff Engineer, Solarflare
Not speaking for my employer; that's the marketing department's job.
They asked us to note that Solarflare product names are trademarked.
^ permalink raw reply
* Re: [PATCH v4] can: kvaser_usb: Add support for Kvaser CAN/USB devices
From: Wolfgang Grandegger @ 2012-09-22 16:02 UTC (permalink / raw)
To: Marc Kleine-Budde
Cc: Olivier Sobrie, linux-can, Kvaser Support, netdev, linux-usb
In-Reply-To: <505C395C.6000504@pengutronix.de>
On 09/21/2012 11:54 AM, Marc Kleine-Budde wrote:
> On 09/20/2012 07:06 AM, Olivier Sobrie wrote:
>> This driver provides support for several Kvaser CAN/USB devices.
>> Such kind of devices supports up to three CAN network interfaces.
>>
>> It has been tested with a Kvaser USB Leaf Light (one network interface)
>> connected to a pch_can interface.
>> The firmware version of the Kvaser device was 2.5.205.
>
> I don't remember, have the USB people already had a look on your driver
> and gave some comments?
IIRC, Oliver Neukum commented on v2. Actually we ignored v3 :(, sorry!
> From the CAN and network point of view looks good, some comments inline.
> Would be fine, if Wolfgang can give comments or Ack about the error
> frame generation.
Olivier already sent candump traces for no cable connected and
short-circuiting CAN high and low. The error handling looked good, IIRC,
at least as good as the firmware can do... more comments inline...
>> List of Kvaser devices supported by the driver:
>> - Kvaser Leaf prototype (P010v2 and v3)
>> - Kvaser Leaf Light (P010v3)
>> - Kvaser Leaf Professional HS
>> - Kvaser Leaf SemiPro HS
>> - Kvaser Leaf Professional LS
>> - Kvaser Leaf Professional SWC
>> - Kvaser Leaf Professional LIN
>> - Kvaser Leaf SemiPro LS
>> - Kvaser Leaf SemiPro SWC
>> - Kvaser Memorator II, Prototype
>> - Kvaser Memorator II HS/HS
>> - Kvaser USBcan Professional HS/HS
>> - Kvaser Leaf Light GI
>> - Kvaser Leaf Professional HS (OBD-II connector)
>> - Kvaser Memorator Professional HS/LS
>> - Kvaser Leaf Light "China"
>> - Kvaser BlackBird SemiPro
>> - Kvaser OEM Mercury
>> - Kvaser OEM Leaf
>> - Kvaser USBcan R
>>
>> Signed-off-by: Olivier Sobrie <olivier@sobrie.be>
>> ---
>> Changes since v3:
>> - add support for CMD_LOG_MESSAGE
>>
>> drivers/net/can/usb/Kconfig | 33 +
>> drivers/net/can/usb/Makefile | 1 +
>> drivers/net/can/usb/kvaser_usb.c | 1555 ++++++++++++++++++++++++++++++++++++++
>> 3 files changed, 1589 insertions(+)
>> create mode 100644 drivers/net/can/usb/kvaser_usb.c
>>
>> diff --git a/drivers/net/can/usb/Kconfig b/drivers/net/can/usb/Kconfig
>> index 0a68768..578955f 100644
>> --- a/drivers/net/can/usb/Kconfig
>> +++ b/drivers/net/can/usb/Kconfig
>> @@ -13,6 +13,39 @@ config CAN_ESD_USB2
>> This driver supports the CAN-USB/2 interface
>> from esd electronic system design gmbh (http://www.esd.eu).
>>
>> +config CAN_KVASER_USB
>> + tristate "Kvaser CAN/USB interface"
>> + ---help---
>> + This driver adds support for Kvaser CAN/USB devices like Kvaser
>> + Leaf Light.
>> +
>> + The driver gives support for the following devices:
>> + - Kvaser Leaf prototype (P010v2 and v3)
>> + - Kvaser Leaf Light (P010v3)
>> + - Kvaser Leaf Professional HS
>> + - Kvaser Leaf SemiPro HS
>> + - Kvaser Leaf Professional LS
>> + - Kvaser Leaf Professional SWC
>> + - Kvaser Leaf Professional LIN
>> + - Kvaser Leaf SemiPro LS
>> + - Kvaser Leaf SemiPro SWC
>> + - Kvaser Memorator II, Prototype
>> + - Kvaser Memorator II HS/HS
>> + - Kvaser USBcan Professional HS/HS
>> + - Kvaser Leaf Light GI
>> + - Kvaser Leaf Professional HS (OBD-II connector)
>> + - Kvaser Memorator Professional HS/LS
>> + - Kvaser Leaf Light "China"
>> + - Kvaser BlackBird SemiPro
>> + - Kvaser OEM Mercury
>> + - Kvaser OEM Leaf
>> + - Kvaser USBcan R
>> +
>> + If unsure, say N.
>> +
>> + To compile this driver as a module, choose M here: the
>> + module will be called kvaser_usb.
>> +
>> config CAN_PEAK_USB
>> tristate "PEAK PCAN-USB/USB Pro interfaces"
>> ---help---
>> diff --git a/drivers/net/can/usb/Makefile b/drivers/net/can/usb/Makefile
>> index da6d1d3..80a2ee4 100644
>> --- a/drivers/net/can/usb/Makefile
>> +++ b/drivers/net/can/usb/Makefile
>> @@ -4,6 +4,7 @@
>>
>> obj-$(CONFIG_CAN_EMS_USB) += ems_usb.o
>> obj-$(CONFIG_CAN_ESD_USB2) += esd_usb2.o
>> +obj-$(CONFIG_CAN_KVASER_USB) += kvaser_usb.o
>> obj-$(CONFIG_CAN_PEAK_USB) += peak_usb/
>>
>> ccflags-$(CONFIG_CAN_DEBUG_DEVICES) := -DDEBUG
>> diff --git a/drivers/net/can/usb/kvaser_usb.c b/drivers/net/can/usb/kvaser_usb.c
>> new file mode 100644
>> index 0000000..3509ca5
>> --- /dev/null
>> +++ b/drivers/net/can/usb/kvaser_usb.c
>> @@ -0,0 +1,1555 @@
>> +/*
>> + * This program is free software; you can redistribute it and/or
>> + * modify it under the terms of the GNU General Public License as
>> + * published by the Free Software Foundation version 2.
>> + *
>> + * Parts of this driver are based on the following:
>> + * - Kvaser linux leaf driver (version 4.78)
>> + * - CAN driver for esd CAN-USB/2
>> + *
>> + * Copyright (C) 2002-2006 KVASER AB, Sweden. All rights reserved.
>> + * Copyright (C) 2010 Matthias Fuchs <matthias.fuchs@esd.eu>, esd gmbh
>> + * Copyright (C) 2012 Olivier Sobrie <olivier@sobrie.be>
>> + */
>> +
>> +#include <linux/init.h>
>> +#include <linux/completion.h>
>> +#include <linux/module.h>
>> +#include <linux/netdevice.h>
>> +#include <linux/usb.h>
>> +
>> +#include <linux/can.h>
>> +#include <linux/can/dev.h>
>> +#include <linux/can/error.h>
>> +
>> +#define MAX_TX_URBS 16
>> +#define MAX_RX_URBS 4
>> +#define START_TIMEOUT 1000 /* msecs */
>> +#define STOP_TIMEOUT 1000 /* msecs */
>> +#define USB_SEND_TIMEOUT 1000 /* msecs */
>> +#define USB_RECV_TIMEOUT 1000 /* msecs */
>> +#define RX_BUFFER_SIZE 3072
>> +#define CAN_USB_CLOCK 8000000
>> +#define MAX_NET_DEVICES 3
>> +
>> +/* Kvaser USB devices */
>> +#define KVASER_VENDOR_ID 0x0bfd
>> +#define USB_LEAF_DEVEL_PRODUCT_ID 10
>> +#define USB_LEAF_LITE_PRODUCT_ID 11
>> +#define USB_LEAF_PRO_PRODUCT_ID 12
>> +#define USB_LEAF_SPRO_PRODUCT_ID 14
>> +#define USB_LEAF_PRO_LS_PRODUCT_ID 15
>> +#define USB_LEAF_PRO_SWC_PRODUCT_ID 16
>> +#define USB_LEAF_PRO_LIN_PRODUCT_ID 17
>> +#define USB_LEAF_SPRO_LS_PRODUCT_ID 18
>> +#define USB_LEAF_SPRO_SWC_PRODUCT_ID 19
>> +#define USB_MEMO2_DEVEL_PRODUCT_ID 22
>> +#define USB_MEMO2_HSHS_PRODUCT_ID 23
>> +#define USB_UPRO_HSHS_PRODUCT_ID 24
>> +#define USB_LEAF_LITE_GI_PRODUCT_ID 25
>> +#define USB_LEAF_PRO_OBDII_PRODUCT_ID 26
>> +#define USB_MEMO2_HSLS_PRODUCT_ID 27
>> +#define USB_LEAF_LITE_CH_PRODUCT_ID 28
>> +#define USB_BLACKBIRD_SPRO_PRODUCT_ID 29
>> +#define USB_OEM_MERCURY_PRODUCT_ID 34
>> +#define USB_OEM_LEAF_PRODUCT_ID 35
>> +#define USB_CAN_R_PRODUCT_ID 39
>> +
>> +/* USB devices features */
>> +#define KVASER_HAS_SILENT_MODE BIT(0)
>> +#define KVASER_HAS_TXRX_ERRORS BIT(1)
>> +
>> +/* Message header size */
>> +#define MSG_HEADER_LEN 2
>> +
>> +/* Can message flags */
>> +#define MSG_FLAG_ERROR_FRAME BIT(0)
>> +#define MSG_FLAG_OVERRUN BIT(1)
>> +#define MSG_FLAG_NERR BIT(2)
>> +#define MSG_FLAG_WAKEUP BIT(3)
>> +#define MSG_FLAG_REMOTE_FRAME BIT(4)
>> +#define MSG_FLAG_RESERVED BIT(5)
>> +#define MSG_FLAG_TX_ACK BIT(6)
>> +#define MSG_FLAG_TX_REQUEST BIT(7)
>> +
>> +/* Can states */
>> +#define M16C_STATE_BUS_RESET BIT(0)
>> +#define M16C_STATE_BUS_ERROR BIT(4)
>> +#define M16C_STATE_BUS_PASSIVE BIT(5)
>> +#define M16C_STATE_BUS_OFF BIT(6)
>> +
>> +/* Can msg ids */
>> +#define CMD_RX_STD_MESSAGE 12
>> +#define CMD_TX_STD_MESSAGE 13
>> +#define CMD_RX_EXT_MESSAGE 14
>> +#define CMD_TX_EXT_MESSAGE 15
>> +#define CMD_SET_BUS_PARAMS 16
>> +#define CMD_GET_BUS_PARAMS 17
>> +#define CMD_GET_BUS_PARAMS_REPLY 18
>> +#define CMD_GET_CHIP_STATE 19
>> +#define CMD_CHIP_STATE_EVENT 20
>> +#define CMD_SET_CTRL_MODE 21
>> +#define CMD_GET_CTRL_MODE 22
>> +#define CMD_GET_CTRL_MODE_REPLY 23
>> +#define CMD_RESET_CHIP 24
>> +#define CMD_RESET_CARD 25
>> +#define CMD_START_CHIP 26
>> +#define CMD_START_CHIP_REPLY 27
>> +#define CMD_STOP_CHIP 28
>> +#define CMD_STOP_CHIP_REPLY 29
>> +#define CMD_GET_CARD_INFO2 32
>> +#define CMD_GET_CARD_INFO 34
>> +#define CMD_GET_CARD_INFO_REPLY 35
>> +#define CMD_GET_SOFTWARE_INFO 38
>> +#define CMD_GET_SOFTWARE_INFO_REPLY 39
>> +#define CMD_ERROR_EVENT 45
>> +#define CMD_FLUSH_QUEUE 48
>> +#define CMD_RESET_ERROR_COUNTER 49
>> +#define CMD_TX_ACKNOWLEDGE 50
>> +#define CMD_CAN_ERROR_EVENT 51
>> +#define CMD_USB_THROTTLE 77
>> +#define CMD_LOG_MESSAGE 106
>> +
>> +/* error factors */
>> +#define M16C_EF_ACKE BIT(0)
>> +#define M16C_EF_CRCE BIT(1)
>> +#define M16C_EF_FORME BIT(2)
>> +#define M16C_EF_STFE BIT(3)
>> +#define M16C_EF_BITE0 BIT(4)
>> +#define M16C_EF_BITE1 BIT(5)
>> +#define M16C_EF_RCVE BIT(6)
>> +#define M16C_EF_TRE BIT(7)
>> +
>> +/* bittiming parameters */
>> +#define KVASER_USB_TSEG1_MIN 1
>> +#define KVASER_USB_TSEG1_MAX 16
>> +#define KVASER_USB_TSEG2_MIN 1
>> +#define KVASER_USB_TSEG2_MAX 8
>> +#define KVASER_USB_SJW_MAX 4
>> +#define KVASER_USB_BRP_MIN 1
>> +#define KVASER_USB_BRP_MAX 64
>> +#define KVASER_USB_BRP_INC 1
>> +
>> +/* ctrl modes */
>> +#define KVASER_CTRL_MODE_NORMAL 1
>> +#define KVASER_CTRL_MODE_SILENT 2
>> +#define KVASER_CTRL_MODE_SELFRECEPTION 3
>> +#define KVASER_CTRL_MODE_OFF 4
>> +
>> +struct kvaser_msg_simple {
>> + u8 tid;
>> + u8 channel;
>> +} __packed;
>> +
>> +struct kvaser_msg_cardinfo {
>> + u8 tid;
>> + u8 nchannels;
>> + __le32 serial_number;
>> + __le32 padding;
>> + __le32 clock_resolution;
>> + __le32 mfgdate;
>> + u8 ean[8];
>> + u8 hw_revision;
>> + u8 usb_hs_mode;
>> + __le16 padding2;
>> +} __packed;
>> +
>> +struct kvaser_msg_cardinfo2 {
>> + u8 tid;
>> + u8 channel;
>> + u8 pcb_id[24];
>> + __le32 oem_unlock_code;
>> +} __packed;
>> +
>> +struct kvaser_msg_softinfo {
>> + u8 tid;
>> + u8 channel;
>> + __le32 sw_options;
>> + __le32 fw_version;
>> + __le16 max_outstanding_tx;
>> + __le16 padding[9];
>> +} __packed;
>> +
>> +struct kvaser_msg_busparams {
>> + u8 tid;
>> + u8 channel;
>> + __le32 bitrate;
>> + u8 tseg1;
>> + u8 tseg2;
>> + u8 sjw;
>> + u8 no_samp;
>> +} __packed;
>> +
>> +struct kvaser_msg_tx_can {
>> + u8 channel;
>> + u8 tid;
>> + u8 msg[14];
>> + u8 padding;
>> + u8 flags;
>> +} __packed;
>> +
>> +struct kvaser_msg_rx_can {
>> + u8 channel;
>> + u8 flag;
>> + __le16 time[3];
>> + u8 msg[14];
>> +} __packed;
>> +
>> +struct kvaser_msg_chip_state_event {
>> + u8 tid;
>> + u8 channel;
>> + __le16 time[3];
>> + u8 tx_errors_count;
>> + u8 rx_errors_count;
>> + u8 status;
>> + u8 padding[3];
>> +} __packed;
>> +
>> +struct kvaser_msg_tx_acknowledge {
>> + u8 channel;
>> + u8 tid;
>> + __le16 time[3];
>> + u8 flags;
>> + u8 time_offset;
>> +} __packed;
>> +
>> +struct kvaser_msg_error_event {
>> + u8 tid;
>> + u8 flags;
>> + __le16 time[3];
>> + u8 channel;
>> + u8 padding;
>> + u8 tx_errors_count;
>> + u8 rx_errors_count;
>> + u8 status;
>> + u8 error_factor;
>> +} __packed;
>> +
>> +struct kvaser_msg_ctrl_mode {
>> + u8 tid;
>> + u8 channel;
>> + u8 ctrl_mode;
>> + u8 padding[3];
>> +} __packed;
>> +
>> +struct kvaser_msg_flush_queue {
>> + u8 tid;
>> + u8 channel;
>> + u8 flags;
>> + u8 padding[3];
>> +} __packed;
>> +
>> +struct kvaser_msg_log_message {
>> + u8 channel;
>> + u8 flags;
>> + __le16 time[3];
>> + u8 dlc;
>> + u8 time_offset;
>> + __le32 id;
>> + u8 data[8];
>> +} __packed;
>> +
>> +struct kvaser_msg {
>> + u8 len;
>> + u8 id;
>> + union {
>> + struct kvaser_msg_simple simple;
>> + struct kvaser_msg_cardinfo cardinfo;
>> + struct kvaser_msg_cardinfo2 cardinfo2;
>> + struct kvaser_msg_softinfo softinfo;
>> + struct kvaser_msg_busparams busparams;
>> + struct kvaser_msg_tx_can tx_can;
>> + struct kvaser_msg_rx_can rx_can;
>> + struct kvaser_msg_chip_state_event chip_state_event;
>> + struct kvaser_msg_tx_acknowledge tx_acknowledge;
>> + struct kvaser_msg_error_event error_event;
>> + struct kvaser_msg_ctrl_mode ctrl_mode;
>> + struct kvaser_msg_flush_queue flush_queue;
>> + struct kvaser_msg_log_message log_message;
>> + } u;
>> +} __packed;
>> +
>> +struct kvaser_usb_tx_urb_context {
>> + struct kvaser_usb_net_priv *priv;
>> + u32 echo_index;
>> + int dlc;
>> +};
>> +
>> +struct kvaser_usb {
>> + struct usb_device *udev;
>> + struct kvaser_usb_net_priv *nets[MAX_NET_DEVICES];
>> +
>> + struct usb_endpoint_descriptor *bulk_in, *bulk_out;
>> + struct usb_anchor rx_submitted;
>> +
>> + u32 fw_version;
>> + unsigned int nchannels;
>> +
>> + bool rxinitdone;
>> + void *rxbuf[MAX_RX_URBS];
>> + dma_addr_t rxbuf_dma[MAX_RX_URBS];
>> +};
>> +
>> +struct kvaser_usb_net_priv {
>> + struct can_priv can;
>> +
>> + atomic_t active_tx_urbs;
>> + struct usb_anchor tx_submitted;
>> + struct kvaser_usb_tx_urb_context tx_contexts[MAX_TX_URBS];
>> +
>> + struct completion start_comp, stop_comp;
>> +
>> + struct kvaser_usb *dev;
>> + struct net_device *netdev;
>> + int channel;
>> +
>> + struct can_berr_counter bec;
>> +};
>> +
>> +static struct usb_device_id kvaser_usb_table[] = {
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_DEVEL_PRODUCT_ID) },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_PRODUCT_ID) },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS |
>> + KVASER_HAS_SILENT_MODE },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS |
>> + KVASER_HAS_SILENT_MODE },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LS_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS |
>> + KVASER_HAS_SILENT_MODE },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_SWC_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS |
>> + KVASER_HAS_SILENT_MODE },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_LIN_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS |
>> + KVASER_HAS_SILENT_MODE },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_LS_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS |
>> + KVASER_HAS_SILENT_MODE },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_SPRO_SWC_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS |
>> + KVASER_HAS_SILENT_MODE },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_DEVEL_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS |
>> + KVASER_HAS_SILENT_MODE },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSHS_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS |
>> + KVASER_HAS_SILENT_MODE },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_UPRO_HSHS_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_GI_PRODUCT_ID) },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_PRO_OBDII_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS |
>> + KVASER_HAS_SILENT_MODE },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_MEMO2_HSLS_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_LEAF_LITE_CH_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_BLACKBIRD_SPRO_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_MERCURY_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_OEM_LEAF_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS },
>> + { USB_DEVICE(KVASER_VENDOR_ID, USB_CAN_R_PRODUCT_ID),
>> + .driver_info = KVASER_HAS_TXRX_ERRORS },
>> + { }
>> +};
>> +MODULE_DEVICE_TABLE(usb, kvaser_usb_table);
>> +
>> +static inline int kvaser_usb_send_msg(const struct kvaser_usb *dev,
>> + struct kvaser_msg *msg)
>> +{
>> + int actual_len;
>> +
>> + return usb_bulk_msg(dev->udev,
>> + usb_sndbulkpipe(dev->udev,
>> + dev->bulk_out->bEndpointAddress),
>> + msg, msg->len, &actual_len,
>> + USB_SEND_TIMEOUT);
>> +}
>> +
>> +static int kvaser_usb_wait_msg(const struct kvaser_usb *dev, u8 id,
>> + struct kvaser_msg *msg)
>> +{
>> + struct kvaser_msg *tmp;
>> + void *buf;
>> + int actual_len;
>> + int err;
>> + int pos = 0;
>> +
>> + buf = kzalloc(RX_BUFFER_SIZE, GFP_KERNEL);
>> + if (!buf)
>> + return -ENOMEM;
>> +
>> + err = usb_bulk_msg(dev->udev,
>> + usb_rcvbulkpipe(dev->udev,
>> + dev->bulk_in->bEndpointAddress),
>> + buf, RX_BUFFER_SIZE, &actual_len,
>> + USB_RECV_TIMEOUT);
>> + if (err < 0)
>> + goto end;
>> +
>> + while (pos <= actual_len - MSG_HEADER_LEN) {
>> + tmp = buf + pos;
>> +
>> + if (!tmp->len)
>> + break;
>> +
>> + if (pos + tmp->len > actual_len) {
>> + dev_err(dev->udev->dev.parent, "Format error\n");
>> + break;
>> + }
>> +
>> + if (tmp->id == id) {
>> + memcpy(msg, tmp, tmp->len);
>> + goto end;
>> + }
>> +
>> + pos += tmp->len;
>> + }
>> +
>> + err = -EINVAL;
>> +
>> +end:
>> + kfree(buf);
>> +
>> + return err;
>> +}
>> +
>> +static int kvaser_usb_send_simple_msg(const struct kvaser_usb *dev,
>> + u8 msg_id, int channel)
>> +{
>> + struct kvaser_msg msg = {
>> + .len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple),
>> + .id = msg_id,
>> + .u.simple.channel = channel,
>> + .u.simple.tid = 0xff,
>> + };
>> +
>> + return kvaser_usb_send_msg(dev, &msg);
>> +}
>> +
>> +static int kvaser_usb_get_software_info(struct kvaser_usb *dev)
>> +{
>> + struct kvaser_msg msg;
>> + int err;
>> +
>> + err = kvaser_usb_send_simple_msg(dev, CMD_GET_SOFTWARE_INFO, 0);
>> + if (err)
>> + return err;
>> +
>> + err = kvaser_usb_wait_msg(dev, CMD_GET_SOFTWARE_INFO_REPLY, &msg);
>> + if (err)
>> + return err;
>> +
>> + dev->fw_version = le32_to_cpu(msg.u.softinfo.fw_version);
>> +
>> + return 0;
>> +}
>> +
>> +static int kvaser_usb_get_card_info(struct kvaser_usb *dev)
>> +{
>> + struct kvaser_msg msg;
>> + int err;
>> +
>> + err = kvaser_usb_send_simple_msg(dev, CMD_GET_CARD_INFO, 0);
>> + if (err)
>> + return err;
>> +
>> + err = kvaser_usb_wait_msg(dev, CMD_GET_CARD_INFO_REPLY, &msg);
>> + if (err)
>> + return err;
>> +
>> + dev->nchannels = msg.u.cardinfo.nchannels;
>> +
>> + return 0;
>> +}
>> +
>> +static void kvaser_usb_tx_acknowledge(const struct kvaser_usb *dev,
>> + const struct kvaser_msg *msg)
>> +{
>> + struct net_device_stats *stats;
>> + struct kvaser_usb_tx_urb_context *context;
>> + struct kvaser_usb_net_priv *priv;
>> + struct sk_buff *skb;
>> + struct can_frame *cf;
>> + u8 channel = msg->u.tx_acknowledge.channel;
>> + u8 tid = msg->u.tx_acknowledge.tid;
>> +
>> + if (channel >= dev->nchannels) {
>> + dev_err(dev->udev->dev.parent,
>> + "Invalid channel number (%d)\n", channel);
>> + return;
>> + }
>> +
>> + priv = dev->nets[channel];
>> +
>> + if (!netif_device_present(priv->netdev))
>> + return;
>> +
>> + stats = &priv->netdev->stats;
>> +
>> + context = &priv->tx_contexts[tid % MAX_TX_URBS];
>> +
>> + /* Sometimes the state change doesn't come after a bus-off event */
>> + if (priv->can.restart_ms &&
>> + (priv->can.state >= CAN_STATE_BUS_OFF)) {
>> + skb = alloc_can_err_skb(priv->netdev, &cf);
>> + if (skb) {
>> + cf->can_id |= CAN_ERR_RESTARTED;
>> + netif_rx(skb);
>> +
>> + stats->rx_packets++;
>> + stats->rx_bytes += cf->can_dlc;
>> + } else {
>> + netdev_err(priv->netdev,
>> + "No memory left for err_skb\n");
>> + }
>> +
>> + priv->can.can_stats.restarts++;
>> + netif_carrier_on(priv->netdev);
>> +
>> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
>> + }
>> +
>> + stats->tx_packets++;
>> + stats->tx_bytes += context->dlc;
>> + can_get_echo_skb(priv->netdev, context->echo_index);
>> +
>> + context->echo_index = MAX_TX_URBS;
>> + atomic_dec(&priv->active_tx_urbs);
>> +
>> + netif_wake_queue(priv->netdev);
>> +}
>> +
>> +static void kvaser_usb_simple_msg_callback(struct urb *urb)
>> +{
>> + struct net_device *netdev = urb->context;
>> +
>> + kfree(urb->transfer_buffer);
>> +
>> + if (urb->status)
>> + netdev_warn(netdev, "urb status received: %d\n",
>> + urb->status);
>> +}
>> +
>> +static int kvaser_usb_simple_msg_async(struct kvaser_usb_net_priv *priv,
>> + u8 msg_id)
>> +{
>> + struct kvaser_usb *dev = priv->dev;
>> + struct net_device *netdev = priv->netdev;
>> + struct kvaser_msg *msg;
>> + struct urb *urb;
>> + void *buf;
>> + int err;
>> +
>> + urb = usb_alloc_urb(0, GFP_ATOMIC);
>> + if (!urb) {
>> + netdev_err(netdev, "No memory left for URBs\n");
>> + return -ENOMEM;
>> + }
>> +
>> + buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
>> + if (!buf) {
>
> Do you have to free the usb you just allocated?
>
>> + netdev_err(netdev, "No memory left for USB buffer\n");
>> + return -ENOMEM;
>> + }
>> +
>> + msg = (struct kvaser_msg *)buf;
>> + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_simple);
>> + msg->id = msg_id;
>> + msg->u.simple.channel = priv->channel;
>> +
>> + usb_fill_bulk_urb(urb, dev->udev,
>> + usb_sndbulkpipe(dev->udev,
>> + dev->bulk_out->bEndpointAddress),
>> + buf, msg->len,
>> + kvaser_usb_simple_msg_callback, priv);
>> + usb_anchor_urb(urb, &priv->tx_submitted);
>> +
>> + err = usb_submit_urb(urb, GFP_ATOMIC);
>> + if (err) {
>> + netdev_err(netdev, "Error transmitting URB\n");
>> + usb_unanchor_urb(urb);
>> + kfree(buf);
>> + return err;
>
> and here?
>
>> + }
>> +
>> + usb_free_urb(urb);
>> +
>> + return 0;
>> +}
>> +
>> +static void kvaser_usb_unlink_tx_urbs(struct kvaser_usb_net_priv *priv)
>> +{
>> + int i;
>> +
>> + usb_kill_anchored_urbs(&priv->tx_submitted);
>> + atomic_set(&priv->active_tx_urbs, 0);
>> +
>> + for (i = 0; i < MAX_TX_URBS; i++)
>> + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
>> +}
>> +
>> +static void kvaser_usb_rx_error(const struct kvaser_usb *dev,
>> + const struct kvaser_msg *msg)
>> +{
>> + struct can_frame *cf;
>> + struct sk_buff *skb;
>> + struct net_device_stats *stats;
>> + struct kvaser_usb_net_priv *priv;
>> + unsigned int new_state;
>> + u8 channel, status, txerr, rxerr, error_factor;
>> +
>> + switch (msg->id) {
>> + case CMD_CAN_ERROR_EVENT:
>> + channel = msg->u.error_event.channel;
>> + status = msg->u.error_event.status;
>> + txerr = msg->u.error_event.tx_errors_count;
>> + rxerr = msg->u.error_event.rx_errors_count;
>> + error_factor = msg->u.error_event.error_factor;
>> + break;
>> + case CMD_LOG_MESSAGE:
>> + channel = msg->u.log_message.channel;
>> + status = msg->u.log_message.data[0];
>> + txerr = msg->u.log_message.data[2];
>> + rxerr = msg->u.log_message.data[3];
>> + error_factor = msg->u.log_message.data[1];
>> + break;
>> + case CMD_CHIP_STATE_EVENT:
>> + channel = msg->u.chip_state_event.channel;
>> + status = msg->u.chip_state_event.status;
>> + txerr = msg->u.chip_state_event.tx_errors_count;
>> + rxerr = msg->u.chip_state_event.rx_errors_count;
>> + error_factor = 0;
>> + break;
>> + default:
>> + dev_err(dev->udev->dev.parent, "Invalid msg id (%d)\n",
>> + msg->id);
>> + return;
>> + }
>> +
>> + if (channel >= dev->nchannels) {
>> + dev_err(dev->udev->dev.parent,
>> + "Invalid channel number (%d)\n", channel);
>> + return;
>> + }
>> +
>> + priv = dev->nets[channel];
>> + stats = &priv->netdev->stats;
>> +
>> + if (status & M16C_STATE_BUS_RESET) {
>> + kvaser_usb_unlink_tx_urbs(priv);
>> + return;
>> + }
>> +
>> + skb = alloc_can_err_skb(priv->netdev, &cf);
>> + if (!skb) {
>> + stats->rx_dropped++;
>> + return;
>> + }
>> +
>> + cf->can_id |= CAN_ERR_BUSERROR;
At state change is *not* a bus error. The line above should e moved into
the "if (error_factor)" block below.
>> +
>> + new_state = priv->can.state;
>> +
>> + netdev_dbg(priv->netdev, "Error status: 0x%02x\n", status);
>> +
>> + if (status & M16C_STATE_BUS_OFF) {
>> + cf->can_id |= CAN_ERR_BUSOFF;
>> +
>> + priv->can.can_stats.bus_off++;
>> + if (!priv->can.restart_ms)
>> + kvaser_usb_simple_msg_async(priv, CMD_STOP_CHIP);
>> +
>> + netif_carrier_off(priv->netdev);
>> +
>> + new_state = CAN_STATE_BUS_OFF;
>> + }
>> +
>> + if (status & M16C_STATE_BUS_PASSIVE) {
>
> else if ()
>
> as bus passive and bus off is mutually exclusive.
>
>> + if (priv->can.state != CAN_STATE_ERROR_PASSIVE) {
>> + cf->can_id |= CAN_ERR_CRTL;
>> +
>> + if ((txerr > 0) || (rxerr > 0))
if (txerr | rxerr) ?
>> + cf->data[1] = (txerr > rxerr)
>> + ? CAN_ERR_CRTL_TX_PASSIVE
>> + : CAN_ERR_CRTL_RX_PASSIVE;
>> + else
>> + cf->data[1] = CAN_ERR_CRTL_TX_PASSIVE |
>> + CAN_ERR_CRTL_RX_PASSIVE;
>> +
>> + priv->can.can_stats.error_passive++;
>> + }
>> +
>> + new_state = CAN_STATE_ERROR_PASSIVE;
>> + }
>> +
>> + if (status == M16C_STATE_BUS_ERROR) {
>> + if ((priv->can.state < CAN_STATE_ERROR_WARNING) &&
>> + ((txerr > 96) || (rxerr > 96))) {
>
> Is is >= 96 ?
Yep.
>> + cf->can_id |= CAN_ERR_CRTL;
>> + cf->data[1] = (txerr > rxerr)
>> + ? CAN_ERR_CRTL_TX_WARNING
>> + : CAN_ERR_CRTL_RX_WARNING;
>> +
>> + priv->can.can_stats.error_warning++;
>> + new_state = CAN_STATE_ERROR_WARNING;
>> + } else if (priv->can.state > CAN_STATE_ERROR_ACTIVE) {
>> + cf->can_id |= CAN_ERR_PROT;
>> + cf->data[2] = CAN_ERR_PROT_ACTIVE;
>> +
>> + new_state = CAN_STATE_ERROR_ACTIVE;
>> + }
>> + }
>> +
>> + if (!status) {
>> + cf->can_id |= CAN_ERR_PROT;
>> + cf->data[2] = CAN_ERR_PROT_ACTIVE;
>> +
>> + new_state = CAN_STATE_ERROR_ACTIVE;
>> + }
>> +
>> + if (priv->can.restart_ms &&
>> + (priv->can.state >= CAN_STATE_BUS_OFF) &&
>> + (new_state < CAN_STATE_BUS_OFF)) {
>> + cf->can_id |= CAN_ERR_RESTARTED;
>> + netif_carrier_on(priv->netdev);
>> +
>> + priv->can.can_stats.restarts++;
>> + }
>> +
>> + if (error_factor) {
>> + priv->can.can_stats.bus_error++;
>> + stats->rx_errors++;
>> +
>> + cf->can_id |= CAN_ERR_PROT;
>> +
>> + if (error_factor & M16C_EF_ACKE)
>> + cf->data[3] |= (CAN_ERR_PROT_LOC_ACK);
>> + if (error_factor & M16C_EF_CRCE)
>> + cf->data[3] |= (CAN_ERR_PROT_LOC_CRC_SEQ |
>> + CAN_ERR_PROT_LOC_CRC_DEL);
>> + if (error_factor & M16C_EF_FORME)
>> + cf->data[2] |= CAN_ERR_PROT_FORM;
>> + if (error_factor & M16C_EF_STFE)
>> + cf->data[2] |= CAN_ERR_PROT_STUFF;
>> + if (error_factor & M16C_EF_BITE0)
>> + cf->data[2] |= CAN_ERR_PROT_BIT0;
>> + if (error_factor & M16C_EF_BITE1)
>> + cf->data[2] |= CAN_ERR_PROT_BIT1;
>> + if (error_factor & M16C_EF_TRE)
>> + cf->data[2] |= CAN_ERR_PROT_TX;
>> + }
>> +
>> + cf->data[6] = txerr;
>> + cf->data[7] = rxerr;
>> +
>> + priv->bec.txerr = txerr;
>> + priv->bec.rxerr = rxerr;
>> +
>> + priv->can.state = new_state;
>> +
>> + netif_rx(skb);
>> +
>> + stats->rx_packets++;
>> + stats->rx_bytes += cf->can_dlc;
>> +}
>> +
>> +static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
>> + const struct kvaser_msg *msg)
>> +{
>> + struct kvaser_usb_net_priv *priv;
>> + struct can_frame *cf;
>> + struct sk_buff *skb;
>> + struct net_device_stats *stats;
>> + u8 channel = msg->u.rx_can.channel;
>> +
>> + if (channel >= dev->nchannels) {
>> + dev_err(dev->udev->dev.parent,
>> + "Invalid channel number (%d)\n", channel);
>> + return;
>> + }
>> +
>> + priv = dev->nets[channel];
>> + stats = &priv->netdev->stats;
>> +
>> + skb = alloc_can_skb(priv->netdev, &cf);
>> + if (!skb) {
>> + stats->tx_dropped++;
>> + return;
>> + }
>> +
>> + cf->can_id = ((msg->u.rx_can.msg[0] & 0x1f) << 6) |
>> + (msg->u.rx_can.msg[1] & 0x3f);
>> + cf->can_dlc = get_can_dlc(msg->u.rx_can.msg[5]);
>> +
>> + if (msg->id == CMD_RX_EXT_MESSAGE) {
>> + cf->can_id <<= 18;
>> + cf->can_id |= ((msg->u.rx_can.msg[2] & 0x0f) << 14) |
>> + ((msg->u.rx_can.msg[3] & 0xff) << 6) |
>> + (msg->u.rx_can.msg[4] & 0x3f);
>> + cf->can_id |= CAN_EFF_FLAG;
>> + }
>> +
>> + if (msg->u.rx_can.flag & MSG_FLAG_REMOTE_FRAME) {
>> + cf->can_id |= CAN_RTR_FLAG;
>> + } else if (msg->u.rx_can.flag & (MSG_FLAG_ERROR_FRAME |
>> + MSG_FLAG_NERR)) {
>> + cf->can_id |= CAN_ERR_FLAG;
>> + cf->can_dlc = CAN_ERR_DLC;
> Please move the error skb creation handling into a subfunction, use
> can_alloc_err_skb() in that function. Please move the:
>
> if (msg->u.rx_can.flag & ...)
>
> up in this function, before the alloc_can_skb().
>
>> +
>> + netdev_err(priv->netdev, "Unknow error (flags: 0x%02x)\n",
>> + msg->u.rx_can.flag);
>> +
>> + stats->rx_errors++;
This an *error* which does normally not happen, IIRC. Therefore I do not
see a need to pass it to the user as error message.
>> + } else if (msg->u.rx_can.flag & MSG_FLAG_OVERRUN) {
>> + cf->can_id = CAN_ERR_FLAG | CAN_ERR_CRTL;
>> + cf->can_dlc = CAN_ERR_DLC;
>> + cf->data[1] = CAN_ERR_CRTL_RX_OVERFLOW;
>> +
>> + stats->rx_over_errors++;
>> + stats->rx_errors++;
>
> This should go into the error skb generation function, too.
>
>> + } else if (!msg->u.rx_can.flag) {
>> + memcpy(cf->data, &msg->u.rx_can.msg[6], cf->can_dlc);
>
> Please don't copy the contents of RTR frames.
>
>> + } else {
>> + kfree_skb(skb);
>
> After you have moved the error skb generation into a seperate function,
> you should get rid of the kfree(skb), too. The function should look like
> this (pseude code):
>
> static void kvaser_usb_rx_can_msg(const struct kvaser_usb *dev,
> const struct kvaser_msg *msg)
> {
> if (channel_invalid())
> return;
>
> if (msg->u.rx_can.flag & ERROR) {
> kvaser_usb_rx_can_err_msg();
> return;
> } else if (msg->u.rx_can.flag & INVALID_FRAME) {
> return;
> }
>
> skb = alloc_can_skb();
>
> /* existing dlc, rtr and data handling code */
> ...
> }
>
>
>> + return;
>> + }
>> +
>> + netif_rx(skb);
>> +
>> + stats->rx_packets++;
>> + stats->rx_bytes += cf->can_dlc;
>> +}
>> +
>> +static void kvaser_usb_start_chip_reply(const struct kvaser_usb *dev,
>> + const struct kvaser_msg *msg)
>> +{
>> + struct kvaser_usb_net_priv *priv;
>> + u8 channel = msg->u.simple.channel;
>> +
>> + if (channel >= dev->nchannels) {
>> + dev_err(dev->udev->dev.parent,
>> + "Invalid channel number (%d)\n", channel);
>> + return;
>> + }
>> +
>> + priv = dev->nets[channel];
>> +
>> + if (completion_done(&priv->start_comp) &&
>> + netif_queue_stopped(priv->netdev)) {
>> + netif_wake_queue(priv->netdev);
>> + } else {
>> + netif_start_queue(priv->netdev);
>> + complete(&priv->start_comp);
>> + }
>> +}
>> +
>> +static void kvaser_usb_stop_chip_reply(const struct kvaser_usb *dev,
>> + const struct kvaser_msg *msg)
>> +{
>> + struct kvaser_usb_net_priv *priv;
>> + u8 channel = msg->u.simple.channel;
>> +
>> + if (channel >= dev->nchannels) {
>> + dev_err(dev->udev->dev.parent,
>> + "Invalid channel number (%d)\n", channel);
>> + return;
>> + }
>> +
>> + priv = dev->nets[channel];
>> +
>> + complete(&priv->stop_comp);
>> +}
>> +
>> +static void kvaser_usb_handle_message(const struct kvaser_usb *dev,
>> + const struct kvaser_msg *msg)
>> +{
>> + switch (msg->id) {
>> + case CMD_START_CHIP_REPLY:
>> + kvaser_usb_start_chip_reply(dev, msg);
>> + break;
>> +
>> + case CMD_STOP_CHIP_REPLY:
>> + kvaser_usb_stop_chip_reply(dev, msg);
>> + break;
>> +
>> + case CMD_RX_STD_MESSAGE:
>> + case CMD_RX_EXT_MESSAGE:
>> + kvaser_usb_rx_can_msg(dev, msg);
>> + break;
>> +
>> + case CMD_CHIP_STATE_EVENT:
>> + case CMD_CAN_ERROR_EVENT:
>> + kvaser_usb_rx_error(dev, msg);
>> + break;
>> +
>> + case CMD_LOG_MESSAGE:
>> + if (msg->u.log_message.flags & MSG_FLAG_ERROR_FRAME)
>> + kvaser_usb_rx_error(dev, msg);
>> + break;
>> +
>> + case CMD_TX_ACKNOWLEDGE:
>> + kvaser_usb_tx_acknowledge(dev, msg);
>> + break;
>> +
>> + default:
>> + dev_warn(dev->udev->dev.parent,
>> + "Unhandled message (%d)\n", msg->id);
>> + break;
>> + }
>> +}
>> +
>> +static void kvaser_usb_read_bulk_callback(struct urb *urb)
>> +{
>> + struct kvaser_usb *dev = urb->context;
>> + struct kvaser_msg *msg;
>> + int pos = 0;
>> + int err, i;
>> +
>> + switch (urb->status) {
>> + case 0:
>> + break;
>> + case -ENOENT:
>> + case -ESHUTDOWN:
>> + return;
>> + default:
>> + dev_info(dev->udev->dev.parent, "Rx URB aborted (%d)\n",
>> + urb->status);
>> + goto resubmit_urb;
>> + }
>> +
>> + while (pos <= urb->actual_length - MSG_HEADER_LEN) {
>> + msg = urb->transfer_buffer + pos;
>> +
>> + if (!msg->len)
>> + break;
>> +
>> + if (pos + msg->len > urb->actual_length) {
>> + dev_err(dev->udev->dev.parent, "Format error\n");
>> + break;
>> + }
>> +
>> + kvaser_usb_handle_message(dev, msg);
>> +
>> + pos += msg->len;
>> + }
>> +
>> +resubmit_urb:
>> + usb_fill_bulk_urb(urb, dev->udev,
>> + usb_rcvbulkpipe(dev->udev,
>> + dev->bulk_in->bEndpointAddress),
>> + urb->transfer_buffer, RX_BUFFER_SIZE,
>> + kvaser_usb_read_bulk_callback, dev);
>> +
>> + err = usb_submit_urb(urb, GFP_ATOMIC);
>> + if (err == -ENODEV) {
>> + for (i = 0; i < dev->nchannels; i++) {
>> + if (!dev->nets[i])
>> + continue;
>> +
>> + netif_device_detach(dev->nets[i]->netdev);
>> + }
>> + } else if (err) {
>> + dev_err(dev->udev->dev.parent,
>> + "Failed resubmitting read bulk urb: %d\n", err);
>> + }
>> +
>> + return;
>> +}
>> +
>> +static int kvaser_usb_setup_rx_urbs(struct kvaser_usb *dev)
>> +{
>> + int i, err = 0;
>> +
>> + if (dev->rxinitdone)
>> + return 0;
>> +
>> + for (i = 0; i < MAX_RX_URBS; i++) {
>> + struct urb *urb = NULL;
>> + u8 *buf = NULL;
>> + dma_addr_t buf_dma;
>> +
>> + urb = usb_alloc_urb(0, GFP_KERNEL);
>> + if (!urb) {
>> + dev_warn(dev->udev->dev.parent,
>> + "No memory left for URBs\n");
>> + err = -ENOMEM;
>> + break;
>> + }
>> +
>> + buf = usb_alloc_coherent(dev->udev, RX_BUFFER_SIZE,
>> + GFP_KERNEL, &buf_dma);
>> + if (!buf) {
>> + dev_warn(dev->udev->dev.parent,
>> + "No memory left for USB buffer\n");
>> + usb_free_urb(urb);
>> + err = -ENOMEM;
>> + break;
>> + }
>> +
>> + usb_fill_bulk_urb(urb, dev->udev,
>> + usb_rcvbulkpipe(dev->udev,
>> + dev->bulk_in->bEndpointAddress),
>> + buf, RX_BUFFER_SIZE,
>> + kvaser_usb_read_bulk_callback,
>> + dev);
>> + urb->transfer_dma = buf_dma;
>> + urb->transfer_flags |= URB_NO_TRANSFER_DMA_MAP;
>> + usb_anchor_urb(urb, &dev->rx_submitted);
>> +
>> + err = usb_submit_urb(urb, GFP_KERNEL);
>> + if (err) {
>> + usb_unanchor_urb(urb);
>> + usb_free_coherent(dev->udev, RX_BUFFER_SIZE, buf,
>> + buf_dma);
>
> Do you have to call usb_free_usb() here, or does the usb frame work take
> care of this?
>
>> + break;
>> + }
>> +
>> + dev->rxbuf[i] = buf;
>> + dev->rxbuf_dma[i] = buf_dma;
>> +
>> + usb_free_urb(urb);
>> + }
>> +
>> + if (i == 0) {
>> + dev_warn(dev->udev->dev.parent,
>> + "Cannot setup read URBs, error %d\n", err);
>> + return err;
>> + } else if (i < MAX_RX_URBS) {
>> + dev_warn(dev->udev->dev.parent,
>> + "RX performances may be slow\n");
>> + }
>> +
>> + dev->rxinitdone = true;
>> +
>> + return 0;
>> +}
>> +
>> +static int kvaser_usb_set_opt_mode(const struct kvaser_usb_net_priv *priv)
>> +{
>> + struct kvaser_msg msg = {
>> + .id = CMD_SET_CTRL_MODE,
>> + .len = MSG_HEADER_LEN +
>> + sizeof(struct kvaser_msg_ctrl_mode),
>> + .u.ctrl_mode.tid = 0xff,
>> + .u.ctrl_mode.channel = priv->channel,
>> + };
>> +
>> + if (priv->can.ctrlmode & CAN_CTRLMODE_LISTENONLY)
>> + msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_SILENT;
>> + else
>> + msg.u.ctrl_mode.ctrl_mode = KVASER_CTRL_MODE_NORMAL;
>> +
>> + return kvaser_usb_send_msg(priv->dev, &msg);
>> +}
>> +
>> +static int kvaser_usb_start_chip(struct kvaser_usb_net_priv *priv)
>> +{
>> + int err;
>> +
>> + init_completion(&priv->start_comp);
>> +
>> + err = kvaser_usb_send_simple_msg(priv->dev, CMD_START_CHIP,
>> + priv->channel);
>> + if (err)
>> + return err;
>> +
>> + if (!wait_for_completion_timeout(&priv->start_comp,
>> + msecs_to_jiffies(START_TIMEOUT)))
>> + return -ETIMEDOUT;
>> +
>> + return 0;
>> +}
>> +
>> +static int kvaser_usb_open(struct net_device *netdev)
>> +{
>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>> + struct kvaser_usb *dev = priv->dev;
>> + int err;
>> +
>> + err = open_candev(netdev);
>> + if (err)
>> + return err;
>> +
>> + err = kvaser_usb_setup_rx_urbs(dev);
>> + if (err)
>> + goto error;
>> +
>> + err = kvaser_usb_set_opt_mode(priv);
>> + if (err)
>> + goto error;
>> +
>> + err = kvaser_usb_start_chip(priv);
>> + if (err) {
>> + netdev_warn(netdev, "Cannot start device, error %d\n", err);
>> + goto error;
>> + }
>> +
>> + priv->can.state = CAN_STATE_ERROR_ACTIVE;
>> +
>> + return 0;
>> +
>> +error:
>> + close_candev(netdev);
>> + return err;
>> +}
>> +
>> +static void kvaser_usb_unlink_all_urbs(struct kvaser_usb *dev)
>> +{
>> + int i;
>> +
>> + usb_kill_anchored_urbs(&dev->rx_submitted);
>> +
>> + for (i = 0; i < MAX_RX_URBS; i++)
>> + usb_free_coherent(dev->udev, RX_BUFFER_SIZE,
>> + dev->rxbuf[i],
>> + dev->rxbuf_dma[i]);
>> +
>> + for (i = 0; i < MAX_NET_DEVICES; i++) {
>> + struct kvaser_usb_net_priv *priv = dev->nets[i];
>> +
>> + if (priv)
>> + kvaser_usb_unlink_tx_urbs(priv);
>> + }
>> +}
>> +
>> +static int kvaser_usb_stop_chip(struct kvaser_usb_net_priv *priv)
>> +{
>> + int err;
>> +
>> + init_completion(&priv->stop_comp);
>> +
>> + err = kvaser_usb_send_simple_msg(priv->dev, CMD_STOP_CHIP,
>> + priv->channel);
>> + if (err)
>> + return err;
>> +
>> + if (!wait_for_completion_timeout(&priv->stop_comp,
>> + msecs_to_jiffies(STOP_TIMEOUT)))
>> + return -ETIMEDOUT;
>> +
>> + return 0;
>> +}
>> +
>> +static int kvaser_usb_flush_queue(struct kvaser_usb_net_priv *priv)
>> +{
>> + struct kvaser_msg msg = {
>> + .id = CMD_FLUSH_QUEUE,
>> + .len = MSG_HEADER_LEN +
>> + sizeof(struct kvaser_msg_flush_queue),
>> + .u.flush_queue.channel = priv->channel,
>> + .u.flush_queue.flags = 0x00,
>> + };
>> +
>> + return kvaser_usb_send_msg(priv->dev, &msg);
>> +}
>> +
>> +static int kvaser_usb_close(struct net_device *netdev)
>> +{
>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>> + struct kvaser_usb *dev = priv->dev;
>> + int err;
>> +
>> + netif_stop_queue(netdev);
>> +
>> + err = kvaser_usb_flush_queue(priv);
>> + if (err)
>> + netdev_warn(netdev, "Cannot flush queue, error %d\n", err);
>> +
>> + if (kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, priv->channel))
>> + netdev_warn(netdev, "Cannot reset card, error %d\n", err);
>> +
>> + err = kvaser_usb_stop_chip(priv);
>> + if (err)
>> + netdev_warn(netdev, "Cannot stop device, error %d\n", err);
>> +
>> + priv->can.state = CAN_STATE_STOPPED;
>> + close_candev(priv->netdev);
>> +
>> + return 0;
>> +}
>> +
>> +static void kvaser_usb_write_bulk_callback(struct urb *urb)
>> +{
>> + struct kvaser_usb_tx_urb_context *context = urb->context;
>> + struct kvaser_usb_net_priv *priv;
>> + struct net_device *netdev;
>> +
>> + if (WARN_ON(!context))
>> + return;
>> +
>> + priv = context->priv;
>> + netdev = priv->netdev;
>> +
>> + kfree(urb->transfer_buffer);
>> +
>> + if (!netif_device_present(netdev))
>> + return;
>> +
>> + if (urb->status)
>> + netdev_info(netdev, "Tx URB aborted (%d)\n", urb->status);
>> +}
>> +
>> +static netdev_tx_t kvaser_usb_start_xmit(struct sk_buff *skb,
>> + struct net_device *netdev)
>> +{
>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>> + struct kvaser_usb *dev = priv->dev;
>> + struct net_device_stats *stats = &netdev->stats;
>> + struct can_frame *cf = (struct can_frame *)skb->data;
>> + struct kvaser_usb_tx_urb_context *context = NULL;
>> + struct urb *urb;
>> + void *buf;
>> + struct kvaser_msg *msg;
>> + int i, err;
>> + int ret = NETDEV_TX_OK;
>> +
>> + if (can_dropped_invalid_skb(netdev, skb))
>> + return NETDEV_TX_OK;
>> +
>> + urb = usb_alloc_urb(0, GFP_ATOMIC);
>> + if (!urb) {
>> + netdev_err(netdev, "No memory left for URBs\n");
>> + stats->tx_dropped++;
>> + dev_kfree_skb(skb);
>> + return NETDEV_TX_OK;
>> + }
>> +
>> + buf = kmalloc(sizeof(struct kvaser_msg), GFP_ATOMIC);
>> + if (!buf) {
>> + netdev_err(netdev, "No memory left for USB buffer\n");
>> + stats->tx_dropped++;
>> + dev_kfree_skb(skb);
> What about the urb?
>> + goto nobufmem;
>> + }
>> +
>> + msg = (struct kvaser_msg *)buf;
>
> nitpick: cast is not needed, as buf is void *
>
>> + msg->len = MSG_HEADER_LEN + sizeof(struct kvaser_msg_tx_can);
>> + msg->u.tx_can.flags = 0;
>> + msg->u.tx_can.channel = priv->channel;
>> +
>> + if (cf->can_id & CAN_EFF_FLAG) {
>> + msg->id = CMD_TX_EXT_MESSAGE;
>> + msg->u.tx_can.msg[0] = (cf->can_id >> 24) & 0x1f;
>> + msg->u.tx_can.msg[1] = (cf->can_id >> 18) & 0x3f;
>> + msg->u.tx_can.msg[2] = (cf->can_id >> 14) & 0x0f;
>> + msg->u.tx_can.msg[3] = (cf->can_id >> 6) & 0xff;
>> + msg->u.tx_can.msg[4] = cf->can_id & 0x3f;
>> + } else {
>> + msg->id = CMD_TX_STD_MESSAGE;
>> + msg->u.tx_can.msg[0] = (cf->can_id >> 6) & 0x1f;
>> + msg->u.tx_can.msg[1] = cf->can_id & 0x3f;
>> + }
>> +
>> + msg->u.tx_can.msg[5] = cf->can_dlc;
>> + memcpy(&msg->u.tx_can.msg[6], cf->data, cf->can_dlc);
>> +
>> + if (cf->can_id & CAN_RTR_FLAG)
>> + msg->u.tx_can.flags |= MSG_FLAG_REMOTE_FRAME;
>> +
>> + for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++) {
>> + if (priv->tx_contexts[i].echo_index == MAX_TX_URBS) {
>> + context = &priv->tx_contexts[i];
>> + break;
>> + }
>> + }
>> +
>> + if (!context) {
>> + netdev_warn(netdev, "cannot find free context\n");
>> + ret = NETDEV_TX_BUSY;
>> + goto releasebuf;
>> + }
>> +
>> + context->priv = priv;
>> + context->echo_index = i;
>> + context->dlc = cf->can_dlc;
>> +
>> + msg->u.tx_can.tid = context->echo_index;
>> +
>> + usb_fill_bulk_urb(urb, dev->udev,
>> + usb_sndbulkpipe(dev->udev,
>> + dev->bulk_out->bEndpointAddress),
>> + buf, msg->len,
>> + kvaser_usb_write_bulk_callback, context);
>> + usb_anchor_urb(urb, &priv->tx_submitted);
>> +
>> + can_put_echo_skb(skb, netdev, context->echo_index);
>> +
>> + atomic_inc(&priv->active_tx_urbs);
>> +
>> + if (atomic_read(&priv->active_tx_urbs) >= MAX_TX_URBS)
>> + netif_stop_queue(netdev);
>> +
>> + err = usb_submit_urb(urb, GFP_ATOMIC);
>> + if (unlikely(err)) {
>> + can_free_echo_skb(netdev, context->echo_index);
>> +
>> + atomic_dec(&priv->active_tx_urbs);
>> + usb_unanchor_urb(urb);
>> +
>> + stats->tx_dropped++;
>> +
>> + if (err == -ENODEV)
>> + netif_device_detach(netdev);
>> + else
>> + netdev_warn(netdev, "Failed tx_urb %d\n", err);
>> +
>> + goto releasebuf;
>> + }
>> +
>> + netdev->trans_start = jiffies;
>
> Is this still needed?
>
>> +
>> + usb_free_urb(urb);
>> +
>> + return NETDEV_TX_OK;
>> +
>> +releasebuf:
>> + kfree(buf);
>> +nobufmem:
>> + usb_free_urb(urb);
>> + return ret;
>> +}
>> +
>> +static const struct net_device_ops kvaser_usb_netdev_ops = {
>> + .ndo_open = kvaser_usb_open,
>> + .ndo_stop = kvaser_usb_close,
>> + .ndo_start_xmit = kvaser_usb_start_xmit,
>> +};
>> +
>> +static struct can_bittiming_const kvaser_usb_bittiming_const = {
>> + .name = "kvaser_usb",
>> + .tseg1_min = KVASER_USB_TSEG1_MIN,
>> + .tseg1_max = KVASER_USB_TSEG1_MAX,
>> + .tseg2_min = KVASER_USB_TSEG2_MIN,
>> + .tseg2_max = KVASER_USB_TSEG2_MAX,
>> + .sjw_max = KVASER_USB_SJW_MAX,
>> + .brp_min = KVASER_USB_BRP_MIN,
>> + .brp_max = KVASER_USB_BRP_MAX,
>> + .brp_inc = KVASER_USB_BRP_INC,
>> +};
>> +
>> +static int kvaser_usb_set_bittiming(struct net_device *netdev)
>> +{
>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>> + struct can_bittiming *bt = &priv->can.bittiming;
>> + struct kvaser_usb *dev = priv->dev;
>> + struct kvaser_msg msg = {
>> + .id = CMD_SET_BUS_PARAMS,
>> + .len = MSG_HEADER_LEN +
>> + sizeof(struct kvaser_msg_busparams),
>> + .u.busparams.channel = priv->channel,
>> + .u.busparams.tid = 0xff,
>> + .u.busparams.bitrate = cpu_to_le32(bt->bitrate),
>> + .u.busparams.sjw = bt->sjw,
>> + .u.busparams.tseg1 = bt->prop_seg + bt->phase_seg1,
>> + .u.busparams.tseg2 = bt->phase_seg2,
>> + };
>> +
>> + if (priv->can.ctrlmode & CAN_CTRLMODE_3_SAMPLES)
>> + msg.u.busparams.no_samp = 3;
>> + else
>> + msg.u.busparams.no_samp = 1;
>> +
>> + return kvaser_usb_send_msg(dev, &msg);
>> +}
>> +
>> +static int kvaser_usb_set_mode(struct net_device *netdev,
>> + enum can_mode mode)
>> +{
>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>> + int err;
>> +
>> + switch (mode) {
>> + case CAN_MODE_START:
>> + err = kvaser_usb_simple_msg_async(priv, CMD_START_CHIP);
>> + if (err)
>> + return err;
>> + break;
>> + default:
>> + return -EOPNOTSUPP;
>> + }
>> +
>> + return 0;
>> +}
>> +
>> +static int kvaser_usb_get_berr_counter(const struct net_device *netdev,
>> + struct can_berr_counter *bec)
>> +{
>> + struct kvaser_usb_net_priv *priv = netdev_priv(netdev);
>> +
>> + *bec = priv->bec;
>> +
>> + return 0;
>> +}
>> +
>> +static int kvaser_usb_init_one(struct usb_interface *intf,
>> + const struct usb_device_id *id, int channel)
>> +{
>> + struct kvaser_usb *dev = usb_get_intfdata(intf);
>> + struct net_device *netdev;
>> + struct kvaser_usb_net_priv *priv;
>> + int i, err;
>> +
>> + netdev = alloc_candev(sizeof(*priv), MAX_TX_URBS);
>> + if (!netdev) {
>> + dev_err(&intf->dev, "Cannot alloc candev\n");
>> + return -ENOMEM;
>> + }
>> +
>> + priv = netdev_priv(netdev);
>> +
>> + init_completion(&priv->start_comp);
>> + init_completion(&priv->stop_comp);
>> +
>> + init_usb_anchor(&priv->tx_submitted);
>> + atomic_set(&priv->active_tx_urbs, 0);
>> +
>> + for (i = 0; i < ARRAY_SIZE(priv->tx_contexts); i++)
>> + priv->tx_contexts[i].echo_index = MAX_TX_URBS;
>> +
>> + priv->dev = dev;
>> + priv->netdev = netdev;
>> + priv->channel = channel;
>> +
>> + priv->can.state = CAN_STATE_STOPPED;
>> + priv->can.clock.freq = CAN_USB_CLOCK;
>> + priv->can.bittiming_const = &kvaser_usb_bittiming_const;
>> + priv->can.do_set_bittiming = kvaser_usb_set_bittiming;
>> + priv->can.do_set_mode = kvaser_usb_set_mode;
>> + if (id->driver_info & KVASER_HAS_TXRX_ERRORS)
>> + priv->can.do_get_berr_counter = kvaser_usb_get_berr_counter;
>> + priv->can.ctrlmode_supported = CAN_CTRLMODE_3_SAMPLES;
>> + if (id->driver_info & KVASER_HAS_SILENT_MODE)
>> + priv->can.ctrlmode_supported |= CAN_CTRLMODE_LISTENONLY;
>> +
>> + netdev->flags |= IFF_ECHO;
>> +
>> + netdev->netdev_ops = &kvaser_usb_netdev_ops;
>> +
>> + SET_NETDEV_DEV(netdev, &intf->dev);
>> +
>> + dev->nets[channel] = priv;
>> +
>> + err = register_candev(netdev);
>> + if (err) {
>> + dev_err(&intf->dev, "Failed to register can device\n");
>> + free_candev(netdev);
>> + return err;
>> + }
>> +
>> + netdev_dbg(netdev, "device registered\n");
>> +
>> + return 0;
>> +}
>> +
>> +static void kvaser_usb_get_endpoints(const struct usb_interface *intf,
>> + struct usb_endpoint_descriptor **in,
>> + struct usb_endpoint_descriptor **out)
>> +{
>> + const struct usb_host_interface *iface_desc;
>> + struct usb_endpoint_descriptor *endpoint;
>> + int i;
>> +
>> + iface_desc = &intf->altsetting[0];
>> +
>> + for (i = 0; i < iface_desc->desc.bNumEndpoints; ++i) {
>> + endpoint = &iface_desc->endpoint[i].desc;
>> +
>> + if (usb_endpoint_is_bulk_in(endpoint))
>> + *in = endpoint;
>> +
>> + if (usb_endpoint_is_bulk_out(endpoint))
>> + *out = endpoint;
>> + }
>> +}
>> +
>> +static int kvaser_usb_probe(struct usb_interface *intf,
>> + const struct usb_device_id *id)
>> +{
>> + struct kvaser_usb *dev;
>> + int err = -ENOMEM;
>> + int i;
>> +
>> + dev = devm_kzalloc(&intf->dev, sizeof(*dev), GFP_KERNEL);
>> + if (!dev)
>> + return -ENOMEM;
>> +
>> + kvaser_usb_get_endpoints(intf, &dev->bulk_in, &dev->bulk_out);
>> + if (!dev->bulk_in || !dev->bulk_out) {
>> + dev_err(&intf->dev, "Cannot get usb endpoint(s)");
>> + return err;
>> + }
>> +
>> + dev->udev = interface_to_usbdev(intf);
>> +
>> + init_usb_anchor(&dev->rx_submitted);
>> +
>> + usb_set_intfdata(intf, dev);
>> +
>> + for (i = 0; i < MAX_NET_DEVICES; i++)
>> + kvaser_usb_send_simple_msg(dev, CMD_RESET_CHIP, i);
>> +
>> + err = kvaser_usb_get_software_info(dev);
>> + if (err) {
>> + dev_err(&intf->dev,
>> + "Cannot get software infos, error %d\n", err);
>> + return err;
>> + }
>> +
>> + err = kvaser_usb_get_card_info(dev);
>> + if (err) {
>> + dev_err(&intf->dev,
>> + "Cannot get card infos, error %d\n", err);
>> + return err;
>> + }
>> +
>> + dev_dbg(&intf->dev, "Firmware version: %d.%d.%d\n",
>> + ((dev->fw_version >> 24) & 0xff),
>> + ((dev->fw_version >> 16) & 0xff),
>> + (dev->fw_version & 0xffff));
>> +
>> + for (i = 0; i < dev->nchannels; i++)
>> + kvaser_usb_init_one(intf, id, i);
Error checking is not needed?
>> +
>> + return 0;
>> +}
>> +
>> +static void kvaser_usb_disconnect(struct usb_interface *intf)
>> +{
>> + struct kvaser_usb *dev = usb_get_intfdata(intf);
>> + int i;
>> +
>> + usb_set_intfdata(intf, NULL);
>> +
>> + if (!dev)
>> + return;
>> +
>> + for (i = 0; i < dev->nchannels; i++) {
>> + if (!dev->nets[i])
>> + continue;
>> +
>> + unregister_netdev(dev->nets[i]->netdev);
>> + }
>> +
>> + kvaser_usb_unlink_all_urbs(dev);
>> +
>> + for (i = 0; i < dev->nchannels; i++)
>> + free_candev(dev->nets[i]->netdev);
>> +}
>> +
>> +static struct usb_driver kvaser_usb_driver = {
>> + .name = "kvaser_usb",
>> + .probe = kvaser_usb_probe,
>> + .disconnect = kvaser_usb_disconnect,
>> + .id_table = kvaser_usb_table
>> +};
>> +
>> +module_usb_driver(kvaser_usb_driver);
>> +
>> +MODULE_AUTHOR("Olivier Sobrie <olivier@sobrie.be>");
>> +MODULE_DESCRIPTION("CAN driver for Kvaser CAN/USB devices");
>> +MODULE_LICENSE("GPL v2");
Wolfgang.
^ permalink raw reply
* Re: [PATCH V2 net-next 4/4] ptp: clarify the clock_name sysfs attribute
From: Jeff Kirsher @ 2012-09-22 16:03 UTC (permalink / raw)
To: Ben Hutchings
Cc: Richard Cochran, netdev, David Miller, Jacob Keller, Jeff Kirsher,
John Stultz, Matthew Vick
In-Reply-To: <1348328688.2521.81.camel@bwh-desktop.uk.solarflarecom.com>
On 09/22/2012 08:44 AM, Ben Hutchings wrote:
> On Sat, 2012-09-22 at 09:42 +0200, Richard Cochran wrote:
>> There has been some confusion among PHC driver authors about the
>> intended purpose of the clock_name attribute. This patch expands the
>> documation in order to clarify how the clock_name field should be
>> understood.
>>
>> Signed-off-by: Richard Cochran <richardcochran@gmail.com>
>> ---
>> Documentation/ABI/testing/sysfs-ptp | 5 ++++-
>> 1 files changed, 4 insertions(+), 1 deletions(-)
>>
>> diff --git a/Documentation/ABI/testing/sysfs-ptp b/Documentation/ABI/testing/sysfs-ptp
>> index d40d2b5..c906488 100644
>> --- a/Documentation/ABI/testing/sysfs-ptp
>> +++ b/Documentation/ABI/testing/sysfs-ptp
>> @@ -19,7 +19,10 @@ Date: September 2010
>> Contact: Richard Cochran <richardcochran@gmail.com>
>> Description:
>> This file contains the name of the PTP hardware clock
>> - as a human readable string.
>> + as a human readable string. The purpose of this
>> + attribute is to provide the user with a "friendly
>> + name" and to help distinguish PHY based devices from
>> + MAC based ones.
> Might also be worth saying that it is not required to be unique. And
> this explanation should also go in the kernel-doc in ptp_clock_kernel.h,
> which is what driver writers are most likely to read.
>
> Ben
FWIW, I agree with Ben.
^ permalink raw reply
* [PATCH v3] lxt PHY: Support for the buggy LXT973 rev A2
From: Christophe Leroy @ 2012-09-22 16:16 UTC (permalink / raw)
To: David S Miller, Richard Cochran; +Cc: netdev, linux-kernel
This patch adds proper handling of the buggy revision A2 of LXT973 phy, adding
precautions linked to ERRATA Item 4:
Revision A2 of LXT973 chip randomly returns the contents of the previous even
register when you read a odd register regularly
Signed-off-by: Christophe Leroy <christophe.leroy@c-s.fr>
diff -u linux-3.5-vanilla/drivers/net/phy/lxt.c linux-3.5/drivers/net/phy/lxt.c
--- linux-3.5-vanilla/drivers/net/phy/lxt.c 2012-07-21 22:58:29.000000000 +0200
+++ linux-3.5/drivers/net/phy/lxt.c 2012-09-15 19:20:34.000000000 +0200
@@ -54,8 +54,12 @@
#define MII_LXT971_ISR 19 /* Interrupt Status Register */
/* register definitions for the 973 */
-#define MII_LXT973_PCR 16 /* Port Configuration Register */
+#define MII_LXT973_PCR 16 /* Port Configuration Register */
#define PCR_FIBER_SELECT 1
+#define MII_LXT973_SFR 27 /* Special Function Register */
+
+#define PHYDEV_PRIV_FIBER 1
+#define PHYDEV_PRIV_REVA2 2
MODULE_DESCRIPTION("Intel LXT PHY driver");
MODULE_AUTHOR("Andy Fleming");
@@ -99,6 +103,9 @@
return err;
}
+/* register definitions for the 973 */
+#define MII_LXT973_PCR 16 /* Port Configuration Register */
+#define PCR_FIBER_SELECT 1
static int lxt971_ack_interrupt(struct phy_device *phydev)
{
@@ -122,9 +129,138 @@
return err;
}
+/*
+ * A2 version of LXT973 chip has an ERRATA: it randomly return the contents
+ * of the previous even register when you read a odd register regularly
+ */
+
+static int lxt973a2_update_link(struct phy_device *phydev)
+{
+ int status;
+ int control;
+ int retry = 8; /* we try 8 times */
+
+ /* Do a fake read */
+ status = phy_read(phydev, MII_BMSR);
+
+ if (status < 0)
+ return status;
+
+ control = phy_read(phydev, MII_BMCR);
+ if (control < 0)
+ return control;
+
+ do {
+ /* Read link and autonegotiation status */
+ status = phy_read(phydev, MII_BMSR);
+ } while (status >= 0 && retry-- && status == control);
+
+ if (status < 0)
+ return status;
+
+ if ((status & BMSR_LSTATUS) == 0)
+ phydev->link = 0;
+ else
+ phydev->link = 1;
+
+ return 0;
+}
+
+int lxt973a2_read_status(struct phy_device *phydev)
+{
+ int adv;
+ int err;
+ int lpa;
+ int lpagb = 0;
+
+ /* Update the link, but return if there was an error */
+ err = lxt973a2_update_link(phydev);
+ if (err)
+ return err;
+
+ if (AUTONEG_ENABLE == phydev->autoneg) {
+ int retry = 1;
+
+ adv = phy_read(phydev, MII_ADVERTISE);
+
+ if (adv < 0)
+ return adv;
+
+ do {
+ lpa = phy_read(phydev, MII_LPA);
+
+ if (lpa < 0)
+ return lpa;
+
+ /* If both registers are equal, it is suspect but not
+ * impossible, hence a new try
+ */
+ } while (lpa == adv && retry--);
+
+ lpa &= adv;
+
+ phydev->speed = SPEED_10;
+ phydev->duplex = DUPLEX_HALF;
+ phydev->pause = phydev->asym_pause = 0;
+
+ if (lpagb & (LPA_1000FULL | LPA_1000HALF)) {
+ phydev->speed = SPEED_1000;
+
+ if (lpagb & LPA_1000FULL)
+ phydev->duplex = DUPLEX_FULL;
+ } else if (lpa & (LPA_100FULL | LPA_100HALF)) {
+ phydev->speed = SPEED_100;
+
+ if (lpa & LPA_100FULL)
+ phydev->duplex = DUPLEX_FULL;
+ } else
+ if (lpa & LPA_10FULL)
+ phydev->duplex = DUPLEX_FULL;
+
+ if (phydev->duplex == DUPLEX_FULL) {
+ phydev->pause = lpa & LPA_PAUSE_CAP ? 1 : 0;
+ phydev->asym_pause = lpa & LPA_PAUSE_ASYM ? 1 : 0;
+ }
+ } else {
+ int bmcr = phy_read(phydev, MII_BMCR);
+
+ if (bmcr < 0)
+ return bmcr;
+
+ if (bmcr & BMCR_FULLDPLX)
+ phydev->duplex = DUPLEX_FULL;
+ else
+ phydev->duplex = DUPLEX_HALF;
+
+ if (bmcr & BMCR_SPEED1000)
+ phydev->speed = SPEED_1000;
+ else if (bmcr & BMCR_SPEED100)
+ phydev->speed = SPEED_100;
+ else
+ phydev->speed = SPEED_10;
+
+ phydev->pause = phydev->asym_pause = 0;
+ }
+
+ return 0;
+}
+
+static int lxt973_read_status(struct phy_device *phydev)
+{
+ return (int)phydev->priv&PHYDEV_PRIV_REVA2 ?
+ lxt973a2_read_status(phydev) :
+ genphy_read_status(phydev);
+}
+
static int lxt973_probe(struct phy_device *phydev)
{
int val = phy_read(phydev, MII_LXT973_PCR);
+ int priv = 0;
+
+ phydev->priv = NULL;
+
+ if (val < 0)
+ return val;
if (val & PCR_FIBER_SELECT) {
/*
@@ -136,17 +272,26 @@
val &= ~BMCR_ANENABLE;
phy_write(phydev, MII_BMCR, val);
/* Remember that the port is in fiber mode. */
- phydev->priv = lxt973_probe;
- } else {
- phydev->priv = NULL;
+ priv |= PHYDEV_PRIV_FIBER;
+ }
+ val = phy_read(phydev, MII_PHYSID2);
+
+ if (val < 0)
+ return val;
+
+ if ((val & 0xf) == 0) { /* rev A2 */
+ dev_info(&phydev->dev, " LXT973 revision A2 has bugs\n");
+ priv |= PHYDEV_PRIV_REVA2;
}
+ phydev->priv = (void *)priv;
return 0;
}
static int lxt973_config_aneg(struct phy_device *phydev)
{
/* Do nothing if port is in fiber mode. */
- return phydev->priv ? 0 : genphy_config_aneg(phydev);
+ return (int)phydev->priv&PHYDEV_PRIV_FIBER ?
+ 0 : genphy_config_aneg(phydev);
}
static struct phy_driver lxt970_driver = {
@@ -184,7 +329,10 @@
.flags = 0,
.probe = lxt973_probe,
.config_aneg = lxt973_config_aneg,
- .read_status = genphy_read_status,
+ .read_status = lxt973_read_status,
+ .suspend = genphy_suspend,
+ .resume = genphy_resume,
+ .isolate = genphy_isolate,
.driver = { .owner = THIS_MODULE,},
};
^ permalink raw reply
* Re: [PATCH v2] lxt PHY: Support for the buggy LXT973 rev A2
From: leroy christophe @ 2012-09-22 16:21 UTC (permalink / raw)
To: Lutz Jaenicke; +Cc: David S Miller, netdev, linux-kernel
In-Reply-To: <20120910181747.GA5960@lutz.bln.innominate.local>
Le 10/09/2012 20:17, Lutz Jaenicke a écrit :
> On Mon, Sep 10, 2012 at 05:45:49PM +0200, Christophe Leroy wrote:
>> This patch adds proper handling of the buggy revision A2 of LXT973 phy, adding
>> precautions linked to ERRATA Item 4:
>>
>> Item 4: MDIO Interface and Repeated Polling
>> Problem: Repeated polling of odd-numbered registers via the MDIO interface
>> randomly returns the contents of the previous even register.
>> Implication: Managed applications may not obtain the correct register contents
>> when a particular register is monitored for device status.
>> Workaround: None.
>> Status: This erratum has been previously fixed (in rev A3)
> Hmm. Were did you get the hardware from? We have been using LXT973 in
> our products and the A2 was replaced by A3 in 2003.
>
> Best regards,
> Lutz
They are custom boards that my company manufactures. Most boards
manufactured before 2006 or 2007 have this buggy chip.
Regards
Christophe
^ permalink raw reply
* Re: [PATCH net-next v2] Take care of xfrm policy when checking dst entries
From: Jan Engelhardt @ 2012-09-22 16:49 UTC (permalink / raw)
To: David Miller
Cc: vyasevich, nicolas.dichtel, eric.dumazet, sri, linux-sctp, netdev
In-Reply-To: <20120910.140105.1099041309239526456.davem@davemloft.net>
On Monday 2012-09-10 20:01, David Miller wrote:
>>
>> So you are perfectly ok with invalidating IPv6 cache when IPv4 table
>> changes, but not invalidating IPv4 cache if IPv6 table changes?
>
>Due to tunneling I can't see how this is avoidable?
>
>We do ipv6 over ipv4, but not vice-versa.
I have a setup here where 6 machines are connected with one another
(most of them) to form 9 IPsec sessions, all of which are ESP6 links -
since native IPv6 is provided - that also handle the site-to-site IPv4
traffic. Does that count?
^ permalink raw reply
* [PATCH V3 net-next 0/4] Two new PTP Hardware Clock features
From: Richard Cochran @ 2012-09-22 17:02 UTC (permalink / raw)
To: netdev
Cc: Ben Hutchings, David Miller, Jacob Keller, Jeff Kirsher,
John Stultz, Matthew Vick
This patch series adds two new features to the PHC code.
* ChangeLog
** V3
- Use the correct parent device in the solarflare driver.
- Expand the sysfs documentation of clock_name.
- Also document the clock_name field in the header file.
** V2
- Preserves the clock_name attribute as it was meant to be, instead
of making any changes to it.
- Covers the registration API change in the brand new solarflare phc
device, which was overlooked in V1.
The first two patches let a user program find out the previously
dialed frequency adjustment. This is primarily useful when restarting
a PTP service, since without this information, the presumably correct
adjustment will bias the new frequency estimation.
The third patch links the phc class device to its parent device within
the driver model and sysfs.
The fourth patch adds a bit more documentation of the sysfs clock_name
attribute. This should help clarify the naming scheme.
Thanks,
Richard
Richard Cochran (4):
ptp: remember the adjusted frequency
ptp: provide the clock's adjusted frequency
ptp: link the phc device to its parent device
ptp: clarify the clock_name sysfs attribute
Documentation/ABI/testing/sysfs-ptp | 6 +++++-
drivers/net/ethernet/freescale/gianfar_ptp.c | 2 +-
drivers/net/ethernet/intel/igb/igb_ptp.c | 3 ++-
drivers/net/ethernet/intel/ixgbe/ixgbe_ptp.c | 3 ++-
drivers/net/ethernet/sfc/ptp.c | 3 ++-
drivers/net/phy/dp83640.c | 2 +-
drivers/ptp/ptp_clock.c | 11 +++++++++--
drivers/ptp/ptp_ixp46x.c | 2 +-
drivers/ptp/ptp_pch.c | 2 +-
drivers/ptp/ptp_private.h | 1 +
include/linux/ptp_clock_kernel.h | 11 ++++++++---
11 files changed, 33 insertions(+), 13 deletions(-)
--
1.7.2.5
^ permalink raw reply
* [PATCH V3 net-next 1/4] ptp: remember the adjusted frequency
From: Richard Cochran @ 2012-09-22 17:02 UTC (permalink / raw)
To: netdev
Cc: Ben Hutchings, David Miller, Jacob Keller, Jeff Kirsher,
John Stultz, Matthew Vick
In-Reply-To: <cover.1348332940.git.richardcochran@gmail.com>
This patch adds a field to the representation of a PTP hardware clock in
order to remember the frequency adjustment value dialed by the user.
Adding this field will let us answer queries in the manner of adjtimex
in a follow on patch.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
drivers/ptp/ptp_clock.c | 1 +
drivers/ptp/ptp_private.h | 1 +
2 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 966875d..67e628e 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -147,6 +147,7 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx)
} else if (tx->modes & ADJ_FREQUENCY) {
err = ops->adjfreq(ops, scaled_ppm_to_ppb(tx->freq));
+ ptp->dialed_frequency = tx->freq;
}
return err;
diff --git a/drivers/ptp/ptp_private.h b/drivers/ptp/ptp_private.h
index 4d5b508..69d3207 100644
--- a/drivers/ptp/ptp_private.h
+++ b/drivers/ptp/ptp_private.h
@@ -45,6 +45,7 @@ struct ptp_clock {
dev_t devid;
int index; /* index into clocks.map */
struct pps_device *pps_source;
+ long dialed_frequency; /* remembers the frequency adjustment */
struct timestamp_event_queue tsevq; /* simple fifo for time stamps */
struct mutex tsevq_mux; /* one process at a time reading the fifo */
wait_queue_head_t tsev_wq;
--
1.7.2.5
^ permalink raw reply related
* [PATCH V3 net-next 2/4] ptp: provide the clock's adjusted frequency
From: Richard Cochran @ 2012-09-22 17:02 UTC (permalink / raw)
To: netdev
Cc: Ben Hutchings, David Miller, Jacob Keller, Jeff Kirsher,
John Stultz, Matthew Vick
In-Reply-To: <cover.1348332940.git.richardcochran@gmail.com>
If the timex.mode field indicates a query, then we provide the value of
the current frequency adjustment.
Signed-off-by: Richard Cochran <richardcochran@gmail.com>
---
drivers/ptp/ptp_clock.c | 5 +++++
1 files changed, 5 insertions(+), 0 deletions(-)
diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
index 67e628e..6f7009a 100644
--- a/drivers/ptp/ptp_clock.c
+++ b/drivers/ptp/ptp_clock.c
@@ -148,6 +148,11 @@ static int ptp_clock_adjtime(struct posix_clock *pc, struct timex *tx)
err = ops->adjfreq(ops, scaled_ppm_to_ppb(tx->freq));
ptp->dialed_frequency = tx->freq;
+
+ } else if (tx->modes == 0) {
+
+ tx->freq = ptp->dialed_frequency;
+ err = 0;
}
return err;
--
1.7.2.5
^ permalink raw reply related
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