* Re: [PATCH net-next-2.6] inetpeer: RCU conversion
From: David Miller @ 2010-06-15 21:25 UTC (permalink / raw)
To: eric.dumazet; +Cc: netdev, paulmck
In-Reply-To: <1276626194.2541.186.camel@edumazet-laptop>
From: Eric Dumazet <eric.dumazet@gmail.com>
Date: Tue, 15 Jun 2010 20:23:14 +0200
> inetpeer currently uses an AVL tree protected by an rwlock.
>
> It's possible to make most lookups use RCU
...
> Signed-off-by: Eric Dumazet <eric.dumazet@gmail.com>
Applied, nice work Eric.
^ permalink raw reply
* Re: [PATCH net-next 4/4] cnic: Fix cnic_cm_abort() error handling.
From: David Miller @ 2010-06-15 21:24 UTC (permalink / raw)
To: mchan; +Cc: netdev
In-Reply-To: <1276628223-27125-4-git-send-email-mchan@broadcom.com>
From: "Michael Chan" <mchan@broadcom.com>
Date: Tue, 15 Jun 2010 11:57:03 -0700
> Fix the code that handles the error case when cnic_cm_abort() cannot
> proceed normally. We cannot just set the csk->state and we must
> go through cnic_ready_to_close() to handle all the conditions. We
> also add error return code in cnic_cm_abort().
>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
> Signed-off-by: Eddie Wai <waie@broadcom.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next 3/4] cnic: Refactor and fix cnic_ready_to_close().
From: David Miller @ 2010-06-15 21:24 UTC (permalink / raw)
To: mchan; +Cc: netdev
In-Reply-To: <1276628223-27125-3-git-send-email-mchan@broadcom.com>
From: "Michael Chan" <mchan@broadcom.com>
Date: Tue, 15 Jun 2010 11:57:02 -0700
> Combine RESET_RECEIVED and RESET_COMP logic and fix race condition
> between these 2 events and cnic_cm_close(). In particular, we need
> to (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) before we
> update csk->state.
>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
> Signed-off-by: Eddie Wai <waie@broadcom.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next 2/4] cnic: Refactor code in cnic_cm_process_kcqe().
From: David Miller @ 2010-06-15 21:24 UTC (permalink / raw)
To: mchan; +Cc: netdev
In-Reply-To: <1276628223-27125-2-git-send-email-mchan@broadcom.com>
From: "Michael Chan" <mchan@broadcom.com>
Date: Tue, 15 Jun 2010 11:57:01 -0700
> Move chip-specific code to the respective chip's ->close_conn() functions
> for better code organization.
>
> Signed-off-by: Michael Chan <mchan@broadcom.com>
> Signed-off-by: Eddie Wai <waie@broadcom.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next 1/4] cnic: Return error code in cnic_cm_close() if unsuccessful.
From: David Miller @ 2010-06-15 21:24 UTC (permalink / raw)
To: mchan; +Cc: netdev
In-Reply-To: <1276628223-27125-1-git-send-email-mchan@broadcom.com>
From: "Michael Chan" <mchan@broadcom.com>
Date: Tue, 15 Jun 2010 11:57:00 -0700
> So that bnx2i can handle the error condition immediately and not have to
> wait for timeout.
>
> Signed-off-by: Michael Chan <mchan@broadcom.com.
> Signed-off-by: Eddie Wai <waie@broadcom.com>
Applied.
^ permalink raw reply
* Re: [net-next-2.6 PATCH] ixgbe: update set_rx_mode to fix issues w/ macvlan
From: David Miller @ 2010-06-15 21:24 UTC (permalink / raw)
To: jeffrey.t.kirsher; +Cc: netdev, gospo, bphilips, xma, alexander.h.duyck
In-Reply-To: <20100615192432.3011.29215.stgit@localhost.localdomain>
From: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Date: Tue, 15 Jun 2010 12:25:48 -0700
> From: Alexander Duyck <alexander.h.duyck@intel.com>
>
> This change corrects issues where macvlan was not correctly triggering
> promiscuous mode on ixgbe due to the filters not being correctly set. It
> also corrects the fact that VF rar filters were being overwritten when the
> PF was reset.
>
> CC: Shirley Ma <xma@us.ibm.com>
> Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
> Tested-by: Emil Tantilov <emil.s.tantilov@intel.com>
> Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
Applied.
^ permalink raw reply
* Re: [PATCH 00/17] netfilter: netfilter update
From: David Miller @ 2010-06-15 21:19 UTC (permalink / raw)
To: kaber; +Cc: netfilter-devel, netdev
In-Reply-To: <1276616323-20880-1-git-send-email-kaber@trash.net>
From: kaber@trash.net
Date: Tue, 15 Jun 2010 17:38:26 +0200
> Please pull from:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-next-2.6.git master
Pulled, thanks Patrick.
^ permalink raw reply
* Re: [PATCH 2/8] user_ns: Introduce user_nsmap_uid and user_ns_map_gid.
From: Serge E. Hallyn @ 2010-06-15 20:58 UTC (permalink / raw)
To: Eric W. Biederman
Cc: David Miller, Linux Containers, Serge Hallyn, Pavel Emelyanov,
netdev
In-Reply-To: <m17hm3hxjw.fsf_-_@fess.ebiederm.org>
Quoting Eric W. Biederman (ebiederm@xmission.com):
>
> Define what happens when a we view a uid from one user_namespace
> in another user_namepece.
>
> - If the user namespaces are the same no mapping is necessary.
>
> - For most cases of difference use overflowuid and overflowgid,
> the uid and gid currently used for 16bit apis when we have a 32bit uid
> that does fit in 16bits. Effectively the situation is the same,
> we want to return a uid or gid that is not assigned to any user.
>
> - For the case when we happen to be mapping the uid or gid of the
> creator of the target user namespace use uid 0 and gid as confusing
Looks good, except for 'uid 0 and gid' in commit msg will be confusing.
Just "use uid and gid 0".
> that user with root is not a problem.
>
> Signed-off-by: Eric W. Biederman <ebiederm@xmission.com>
Acked-by: Serge E. Hallyn <serue@us.ibm.com>
Mind you, like you I *am* still conflicted.
I believe the ideal behavior for the case where we're looking up a mapping
for a uid in a namespace created by ns, would be to return the creator's
uid, but then also support returning the POSIX capabilities targeted at
ns, which would be the empty set.
The path leading there is to start with this patch, then support sending
full credentials, and then we can modify this behavior.
(IMO)
thanks for pushing this.
-serge
> ---
> include/linux/user_namespace.h | 14 ++++++++++++
> kernel/user_namespace.c | 44 ++++++++++++++++++++++++++++++++++++++++
> 2 files changed, 58 insertions(+), 0 deletions(-)
>
> diff --git a/include/linux/user_namespace.h b/include/linux/user_namespace.h
> index cc4f453..8178156 100644
> --- a/include/linux/user_namespace.h
> +++ b/include/linux/user_namespace.h
> @@ -36,6 +36,9 @@ static inline void put_user_ns(struct user_namespace *ns)
> kref_put(&ns->kref, free_user_ns);
> }
>
> +uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid);
> +gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid);
> +
> #else
>
> static inline struct user_namespace *get_user_ns(struct user_namespace *ns)
> @@ -52,6 +55,17 @@ static inline void put_user_ns(struct user_namespace *ns)
> {
> }
>
> +static inline uid_t user_ns_map_uid(struct user_namespace *to,
> + const struct cred *cred, uid_t uid)
> +{
> + return uid;
> +}
> +static inline gid_t user_ns_map_gid(struct user_namespace *to,
> + const struct cred *cred, gid_t gid)
> +{
> + return gid;
> +}
> +
> #endif
>
> #endif /* _LINUX_USER_H */
> diff --git a/kernel/user_namespace.c b/kernel/user_namespace.c
> index 076c7c8..825abfb 100644
> --- a/kernel/user_namespace.c
> +++ b/kernel/user_namespace.c
> @@ -9,6 +9,7 @@
> #include <linux/nsproxy.h>
> #include <linux/slab.h>
> #include <linux/user_namespace.h>
> +#include <linux/highuid.h>
> #include <linux/cred.h>
>
> /*
> @@ -82,3 +83,46 @@ void free_user_ns(struct kref *kref)
> schedule_work(&ns->destroyer);
> }
> EXPORT_SYMBOL(free_user_ns);
> +
> +uid_t user_ns_map_uid(struct user_namespace *to, const struct cred *cred, uid_t uid)
> +{
> + struct user_namespace *tmp;
> +
> + if (likely(to == cred->user->user_ns))
> + return uid;
> +
> +
> + /* Is cred->user the creator of the target user_ns
> + * or the creator of one of it's parents?
> + */
> + for ( tmp = to; tmp != &init_user_ns;
> + tmp = tmp->creator->user_ns ) {
> + if (cred->user == tmp->creator) {
> + return (uid_t)0;
> + }
> + }
> +
> + /* No useful relationship so no mapping */
> + return overflowuid;
> +}
> +
> +gid_t user_ns_map_gid(struct user_namespace *to, const struct cred *cred, gid_t gid)
> +{
> + struct user_namespace *tmp;
> +
> + if (likely(to == cred->user->user_ns))
> + return gid;
> +
> + /* Is cred->user the creator of the target user_ns
> + * or the creator of one of it's parents?
> + */
> + for ( tmp = to; tmp != &init_user_ns;
> + tmp = tmp->creator->user_ns ) {
> + if (cred->user == tmp->creator) {
> + return (gid_t)0;
> + }
> + }
> +
> + /* No useful relationship so no mapping */
> + return overflowgid;
> +}
> --
> 1.6.5.2.143.g8cc62
>
> _______________________________________________
> Containers mailing list
> Containers@lists.linux-foundation.org
> https://lists.linux-foundation.org/mailman/listinfo/containers
^ permalink raw reply
* [net-next-2.6 PATCH] ixgbe: update set_rx_mode to fix issues w/ macvlan
From: Jeff Kirsher @ 2010-06-15 19:25 UTC (permalink / raw)
To: davem; +Cc: netdev, gospo, bphilips, Shirley Ma, Alexander Duyck,
Jeff Kirsher
From: Alexander Duyck <alexander.h.duyck@intel.com>
This change corrects issues where macvlan was not correctly triggering
promiscuous mode on ixgbe due to the filters not being correctly set. It
also corrects the fact that VF rar filters were being overwritten when the
PF was reset.
CC: Shirley Ma <xma@us.ibm.com>
Signed-off-by: Alexander Duyck <alexander.h.duyck@intel.com>
Tested-by: Emil Tantilov <emil.s.tantilov@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ixgbe/ixgbe.h | 1
drivers/net/ixgbe/ixgbe_main.c | 88 +++++++++++++++++++++++++++++++++------
drivers/net/ixgbe/ixgbe_sriov.c | 16 ++-----
3 files changed, 79 insertions(+), 26 deletions(-)
diff --git a/drivers/net/ixgbe/ixgbe.h b/drivers/net/ixgbe/ixgbe.h
index 9270089..9e15eb9 100644
--- a/drivers/net/ixgbe/ixgbe.h
+++ b/drivers/net/ixgbe/ixgbe.h
@@ -110,7 +110,6 @@ struct vf_data_storage {
u16 vlans_enabled;
bool clear_to_send;
bool pf_set_mac;
- int rar;
u16 pf_vlan; /* When set, guest VLAN config not allowed. */
u16 pf_qos;
};
diff --git a/drivers/net/ixgbe/ixgbe_main.c b/drivers/net/ixgbe/ixgbe_main.c
index 9cca737..ebc4b04 100644
--- a/drivers/net/ixgbe/ixgbe_main.c
+++ b/drivers/net/ixgbe/ixgbe_main.c
@@ -2992,6 +2992,48 @@ static void ixgbe_restore_vlan(struct ixgbe_adapter *adapter)
}
/**
+ * ixgbe_write_uc_addr_list - write unicast addresses to RAR table
+ * @netdev: network interface device structure
+ *
+ * Writes unicast address list to the RAR table.
+ * Returns: -ENOMEM on failure/insufficient address space
+ * 0 on no addresses written
+ * X on writing X addresses to the RAR table
+ **/
+static int ixgbe_write_uc_addr_list(struct net_device *netdev)
+{
+ struct ixgbe_adapter *adapter = netdev_priv(netdev);
+ struct ixgbe_hw *hw = &adapter->hw;
+ unsigned int vfn = adapter->num_vfs;
+ unsigned int rar_entries = hw->mac.num_rar_entries - (vfn + 1);
+ int count = 0;
+
+ /* return ENOMEM indicating insufficient memory for addresses */
+ if (netdev_uc_count(netdev) > rar_entries)
+ return -ENOMEM;
+
+ if (!netdev_uc_empty(netdev) && rar_entries) {
+ struct netdev_hw_addr *ha;
+ /* return error if we do not support writing to RAR table */
+ if (!hw->mac.ops.set_rar)
+ return -ENOMEM;
+
+ netdev_for_each_uc_addr(ha, netdev) {
+ if (!rar_entries)
+ break;
+ hw->mac.ops.set_rar(hw, rar_entries--, ha->addr,
+ vfn, IXGBE_RAH_AV);
+ count++;
+ }
+ }
+ /* write the addresses in reverse order to avoid write combining */
+ for (; rar_entries > 0 ; rar_entries--)
+ hw->mac.ops.clear_rar(hw, rar_entries);
+
+ return count;
+}
+
+/**
* ixgbe_set_rx_mode - Unicast, Multicast and Promiscuous mode set
* @netdev: network interface device structure
*
@@ -3004,38 +3046,58 @@ void ixgbe_set_rx_mode(struct net_device *netdev)
{
struct ixgbe_adapter *adapter = netdev_priv(netdev);
struct ixgbe_hw *hw = &adapter->hw;
- u32 fctrl;
+ u32 fctrl, vmolr = IXGBE_VMOLR_BAM | IXGBE_VMOLR_AUPE;
+ int count;
/* Check for Promiscuous and All Multicast modes */
fctrl = IXGBE_READ_REG(hw, IXGBE_FCTRL);
+ /* clear the bits we are changing the status of */
+ fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+
if (netdev->flags & IFF_PROMISC) {
hw->addr_ctrl.user_set_promisc = true;
fctrl |= (IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+ vmolr |= (IXGBE_VMOLR_ROPE | IXGBE_VMOLR_MPE);
/* don't hardware filter vlans in promisc mode */
ixgbe_vlan_filter_disable(adapter);
} else {
if (netdev->flags & IFF_ALLMULTI) {
fctrl |= IXGBE_FCTRL_MPE;
- fctrl &= ~IXGBE_FCTRL_UPE;
- } else if (!hw->addr_ctrl.uc_set_promisc) {
- fctrl &= ~(IXGBE_FCTRL_UPE | IXGBE_FCTRL_MPE);
+ vmolr |= IXGBE_VMOLR_MPE;
+ } else {
+ /*
+ * Write addresses to the MTA, if the attempt fails
+ * then we should just turn on promiscous mode so
+ * that we can at least receive multicast traffic
+ */
+ hw->mac.ops.update_mc_addr_list(hw, netdev);
+ vmolr |= IXGBE_VMOLR_ROMPE;
}
ixgbe_vlan_filter_enable(adapter);
hw->addr_ctrl.user_set_promisc = false;
+ /*
+ * Write addresses to available RAR registers, if there is not
+ * sufficient space to store all the addresses then enable
+ * unicast promiscous mode
+ */
+ count = ixgbe_write_uc_addr_list(netdev);
+ if (count < 0) {
+ fctrl |= IXGBE_FCTRL_UPE;
+ vmolr |= IXGBE_VMOLR_ROPE;
+ }
}
- IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
-
- /* reprogram secondary unicast list */
- hw->mac.ops.update_uc_addr_list(hw, netdev);
-
- /* reprogram multicast list */
- hw->mac.ops.update_mc_addr_list(hw, netdev);
-
- if (adapter->num_vfs)
+ if (adapter->num_vfs) {
ixgbe_restore_vf_multicasts(adapter);
+ vmolr |= IXGBE_READ_REG(hw, IXGBE_VMOLR(adapter->num_vfs)) &
+ ~(IXGBE_VMOLR_MPE | IXGBE_VMOLR_ROMPE |
+ IXGBE_VMOLR_ROPE);
+ IXGBE_WRITE_REG(hw, IXGBE_VMOLR(adapter->num_vfs), vmolr);
+ }
+
+ IXGBE_WRITE_REG(hw, IXGBE_FCTRL, fctrl);
}
static void ixgbe_napi_enable_all(struct ixgbe_adapter *adapter)
diff --git a/drivers/net/ixgbe/ixgbe_sriov.c b/drivers/net/ixgbe/ixgbe_sriov.c
index 66f6e62..6e6dee0 100644
--- a/drivers/net/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ixgbe/ixgbe_sriov.c
@@ -137,6 +137,7 @@ static void ixgbe_set_vmvir(struct ixgbe_adapter *adapter, u32 vid, u32 vf)
inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
{
struct ixgbe_hw *hw = &adapter->hw;
+ int rar_entry = hw->mac.num_rar_entries - (vf + 1);
/* reset offloads to defaults */
if (adapter->vfinfo[vf].pf_vlan) {
@@ -158,26 +159,17 @@ inline void ixgbe_vf_reset_event(struct ixgbe_adapter *adapter, u32 vf)
/* Flush and reset the mta with the new values */
ixgbe_set_rx_mode(adapter->netdev);
- if (adapter->vfinfo[vf].rar > 0) {
- adapter->hw.mac.ops.clear_rar(&adapter->hw,
- adapter->vfinfo[vf].rar);
- adapter->vfinfo[vf].rar = -1;
- }
+ hw->mac.ops.clear_rar(hw, rar_entry);
}
int ixgbe_set_vf_mac(struct ixgbe_adapter *adapter,
int vf, unsigned char *mac_addr)
{
struct ixgbe_hw *hw = &adapter->hw;
-
- adapter->vfinfo[vf].rar = hw->mac.ops.set_rar(hw, vf + 1, mac_addr,
- vf, IXGBE_RAH_AV);
- if (adapter->vfinfo[vf].rar < 0) {
- e_err("Could not set MAC Filter for VF %d\n", vf);
- return -1;
- }
+ int rar_entry = hw->mac.num_rar_entries - (vf + 1);
memcpy(adapter->vfinfo[vf].vf_mac_addresses, mac_addr, 6);
+ hw->mac.ops.set_rar(hw, rar_entry, mac_addr, vf, IXGBE_RAH_AV);
return 0;
}
^ permalink raw reply related
* [net-2.6 PATCH] ixgbe: add comment on SFP+ ID for Active DA
From: Jeff Kirsher @ 2010-06-15 19:23 UTC (permalink / raw)
To: davem; +Cc: netdev, gospo, bphilips, Don Skidmore, Jeff Kirsher
From: Don Skidmore <donald.c.skidmore@intel.com>
These comments were forgotten in the initial patch to add this
functionality. This patch corrects that.
Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ixgbe/ixgbe_phy.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ixgbe/ixgbe_phy.c b/drivers/net/ixgbe/ixgbe_phy.c
index 09e1911..48325a5 100644
--- a/drivers/net/ixgbe/ixgbe_phy.c
+++ b/drivers/net/ixgbe/ixgbe_phy.c
@@ -575,6 +575,8 @@ s32 ixgbe_identify_sfp_module_generic(struct ixgbe_hw *hw)
* 4 SFP_DA_CORE1 - 82599-specific
* 5 SFP_SR/LR_CORE0 - 82599-specific
* 6 SFP_SR/LR_CORE1 - 82599-specific
+ * 7 SFP_act_lmt_DA_CORE0 - 82599-specific
+ * 8 SFP_act_lmt_DA_CORE1 - 82599-specific
*/
if (hw->mac.type == ixgbe_mac_82598EB) {
if (cable_tech & IXGBE_SFF_DA_PASSIVE_CABLE)
^ permalink raw reply related
* Re: [PATCH 08/12] ptp: Added a brand new class driver for ptp clocks.
From: Grant Likely @ 2010-06-15 19:11 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev, devicetree-discuss, linuxppc-dev, linux-arm-kernel,
Krzysztof Halasa, Thomas Gleixner
In-Reply-To: <4a030d2bace90f089f2f3f61496b918c6f1dfb52.1276615626.git.richard.cochran@omicron.at>
On Tue, Jun 15, 2010 at 10:09 AM, Richard Cochran
<richardcochran@gmail.com> wrote:
> This patch adds an infrastructure for hardware clocks that implement
> IEEE 1588, the Precision Time Protocol (PTP). A class driver offers a
> registration method to particular hardware clock drivers. Each clock is
> exposed to user space as a character device with ioctls that allow tuning
> of the PTP clock.
>
> Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
Hi Richard,
Some more comments on this patch...
> ---
> Documentation/ptp/ptp.txt | 95 +++++++
> Documentation/ptp/testptp.c | 269 ++++++++++++++++++++
> Documentation/ptp/testptp.mk | 33 +++
> drivers/Kconfig | 2 +
> drivers/Makefile | 1 +
> drivers/ptp/Kconfig | 26 ++
> drivers/ptp/Makefile | 5 +
> drivers/ptp/ptp_clock.c | 514 ++++++++++++++++++++++++++++++++++++++
> include/linux/Kbuild | 1 +
> include/linux/ptp_clock.h | 79 ++++++
> include/linux/ptp_clock_kernel.h | 137 ++++++++++
> 11 files changed, 1162 insertions(+), 0 deletions(-)
> create mode 100644 Documentation/ptp/ptp.txt
> create mode 100644 Documentation/ptp/testptp.c
> create mode 100644 Documentation/ptp/testptp.mk
> create mode 100644 drivers/ptp/Kconfig
> create mode 100644 drivers/ptp/Makefile
> create mode 100644 drivers/ptp/ptp_clock.c
> create mode 100644 include/linux/ptp_clock.h
> create mode 100644 include/linux/ptp_clock_kernel.h
>
> diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
> new file mode 100644
> index 0000000..b86695c
> --- /dev/null
> +++ b/drivers/ptp/Makefile
> @@ -0,0 +1,5 @@
> +#
> +# Makefile for PTP 1588 clock support.
> +#
> +
> +obj-$(CONFIG_PTP_1588_CLOCK) += ptp_clock.o
> diff --git a/drivers/ptp/ptp_clock.c b/drivers/ptp/ptp_clock.c
> new file mode 100644
> index 0000000..4753bf3
> --- /dev/null
> +++ b/drivers/ptp/ptp_clock.c
> @@ -0,0 +1,514 @@
> +/*
> + * PTP 1588 clock support
> + *
> + * Partially adapted from the Linux PPS driver.
> + *
> + * Copyright (C) 2010 OMICRON electronics GmbH
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#include <linux/bitops.h>
> +#include <linux/cdev.h>
> +#include <linux/device.h>
> +#include <linux/init.h>
> +#include <linux/kernel.h>
> +#include <linux/list.h>
> +#include <linux/module.h>
> +#include <linux/poll.h>
> +#include <linux/sched.h>
> +#include <linux/slab.h>
> +#include <linux/uaccess.h>
> +
> +#include <linux/ptp_clock_kernel.h>
> +#include <linux/ptp_clock.h>
> +
> +#define PTP_MAX_ALARMS 4
> +#define PTP_MAX_CLOCKS BITS_PER_LONG
> +#define PTP_MAX_TIMESTAMPS 128
> +
> +struct alarm {
> + struct pid *pid;
> + int sig;
> +};
> +
> +struct timestamp_event_queue {
> + struct ptp_extts_event buf[PTP_MAX_TIMESTAMPS];
> + int head;
> + int tail;
> + int overflow;
> +};
> +
> +struct ptp_clock {
> + struct list_head list;
> + struct cdev cdev;
> + struct device *dev;
> + struct ptp_clock_info *info;
> + dev_t devid;
> + int index; /* index into clocks.map, also the minor number */
> +
> + struct alarm alarm[PTP_MAX_ALARMS];
> + struct mutex alarm_mux; /* one process at a time setting an alarm */
> +
> + 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;
> +};
> +
> +/* private globals */
> +
> +static const struct file_operations ptp_fops;
> +static dev_t ptp_devt;
> +static struct class *ptp_class;
> +
> +static struct {
> + struct list_head list;
> + DECLARE_BITMAP(map, PTP_MAX_CLOCKS);
> +} clocks;
> +static DEFINE_SPINLOCK(clocks_lock); /* protects 'clocks' */
Doesn't appear that clocks is manipulated at atomic context. Mutex instead?
> +
> +/* time stamp event queue operations */
> +
> +static inline int queue_cnt(struct timestamp_event_queue *q)
> +{
> + int cnt = q->tail - q->head;
> + return cnt < 0 ? PTP_MAX_TIMESTAMPS + cnt : cnt;
> +}
> +
> +static inline int queue_free(struct timestamp_event_queue *q)
> +{
> + return PTP_MAX_TIMESTAMPS - queue_cnt(q) - 1;
> +}
> +
> +static void enqueue_external_timestamp(struct timestamp_event_queue *queue,
> + struct ptp_clock_event *src)
> +{
> + struct ptp_extts_event *dst;
> + u32 remainder;
> +
> + dst = &queue->buf[queue->tail];
> +
> + dst->index = src->index;
> + dst->ts.tv_sec = div_u64_rem(src->timestamp, 1000000000, &remainder);
> + dst->ts.tv_nsec = remainder;
> +
> + if (!queue_free(queue))
> + queue->overflow++;
> +
> + queue->tail = (queue->tail + 1) % PTP_MAX_TIMESTAMPS;
> +}
> +
> +/* public interface */
> +
> +struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info)
> +{
> + struct ptp_clock *ptp;
> + int err = 0, index, major = MAJOR(ptp_devt);
> + unsigned long flags;
> +
> + if (info->n_alarm > PTP_MAX_ALARMS)
> + return ERR_PTR(-EINVAL);
Okay, this is my opinion here, and other maintainers may disagree with
me, but the ERR_PTR() pattern is a horrible idea. It is non-obvious
when reading code when the pattern is used, and the compiler will not
catch misinterpretation of the return value for you. Please don't add
new instances of using it. Just return NULL on error and log it with
printk() or pr_error(). Very seldom do I find the actual error code
to be actually useful anyway. Generally callers only care about
whether or not the operation succeeded.
> +
> + /* Find a free clock slot and reserve it. */
> + err = -EBUSY;
> + spin_lock_irqsave(&clocks_lock, flags);
> + index = find_first_zero_bit(clocks.map, PTP_MAX_CLOCKS);
> + if (index < PTP_MAX_CLOCKS) {
> + set_bit(index, clocks.map);
> + spin_unlock_irqrestore(&clocks_lock, flags);
> + } else {
> + spin_unlock_irqrestore(&clocks_lock, flags);
> + goto no_clock;
> + }
If the spinlock is changed to a mutex that is held for the entire
function call, then the logic here can be simpler.
> +
> + /* Initialize a clock structure. */
> + err = -ENOMEM;
> + ptp = kzalloc(sizeof(struct ptp_clock), GFP_KERNEL);
> + if (ptp == NULL)
> + goto no_memory;
> +
> + ptp->info = info;
> + ptp->devid = MKDEV(major, index);
> + ptp->index = index;
> + mutex_init(&ptp->alarm_mux);
> + mutex_init(&ptp->tsevq_mux);
> + init_waitqueue_head(&ptp->tsev_wq);
> +
> + /* Create a new device in our class. */
> + ptp->dev = device_create(ptp_class, NULL, ptp->devid, ptp,
> + "ptp_clock_%d", ptp->index);
> + if (IS_ERR(ptp->dev))
> + goto no_device;
> +
> + dev_set_drvdata(ptp->dev, ptp);
> +
> + /* Register a character device. */
> + cdev_init(&ptp->cdev, &ptp_fops);
> + ptp->cdev.owner = info->owner;
> + err = cdev_add(&ptp->cdev, ptp->devid, 1);
> + if (err)
> + goto no_cdev;
> +
> + /* Clock is ready, add it into the list. */
> + spin_lock_irqsave(&clocks_lock, flags);
> + list_add(&ptp->list, &clocks.list);
> + spin_unlock_irqrestore(&clocks_lock, flags);
> +
> + return ptp;
> +
> +no_cdev:
> + device_destroy(ptp_class, ptp->devid);
> +no_device:
> + mutex_destroy(&ptp->alarm_mux);
> + mutex_destroy(&ptp->tsevq_mux);
> + kfree(ptp);
> +no_memory:
> + spin_lock_irqsave(&clocks_lock, flags);
> + clear_bit(index, clocks.map);
> + spin_unlock_irqrestore(&clocks_lock, flags);
> +no_clock:
> + return ERR_PTR(err);
> +}
> +EXPORT_SYMBOL(ptp_clock_register);
> +
> +int ptp_clock_unregister(struct ptp_clock *ptp)
> +{
> + unsigned long flags;
> +
> + /* Release the clock's resources. */
> + cdev_del(&ptp->cdev);
> + device_destroy(ptp_class, ptp->devid);
> + mutex_destroy(&ptp->alarm_mux);
> + mutex_destroy(&ptp->tsevq_mux);
> +
> + /* Remove the clock from the list. */
> + spin_lock_irqsave(&clocks_lock, flags);
> + list_del(&ptp->list);
> + clear_bit(ptp->index, clocks.map);
> + spin_unlock_irqrestore(&clocks_lock, flags);
> +
> + kfree(ptp);
> +
> + return 0;
> +}
> +EXPORT_SYMBOL(ptp_clock_unregister);
> +
> +void ptp_clock_event(struct ptp_clock *ptp, struct ptp_clock_event *event)
> +{
> + switch (event->type) {
> +
> + case PTP_CLOCK_ALARM:
> + kill_pid(ptp->alarm[event->index].pid,
> + ptp->alarm[event->index].sig, 1);
> + break;
> +
> + case PTP_CLOCK_EXTTS:
> + enqueue_external_timestamp(&ptp->tsevq, event);
> + wake_up_interruptible(&ptp->tsev_wq);
> + break;
> +
> + case PTP_CLOCK_PPS:
> + break;
> + }
> +}
> +EXPORT_SYMBOL(ptp_clock_event);
> +
> +/* character device operations */
> +
> +static int ptp_ioctl(struct inode *node, struct file *fp,
> + unsigned int cmd, unsigned long arg)
> +{
> + struct ptp_clock_caps caps;
> + struct ptp_clock_request req;
> + struct ptp_clock_timer timer;
> + struct ptp_clock *ptp = fp->private_data;
> + struct ptp_clock_info *ops = ptp->info;
> + void *priv = ops->priv;
> + struct timespec ts;
> + int flags, index;
> + int err = 0;
> +
> + switch (cmd) {
> +
> + case PTP_CLOCK_APIVERS:
> + err = put_user(PTP_CLOCK_VERSION, (u32 __user *)arg);
> + break;
> +
> + case PTP_CLOCK_ADJFREQ:
> + if (!capable(CAP_SYS_TIME))
> + return -EPERM;
> + err = ops->adjfreq(priv, arg);
> + break;
> +
> + case PTP_CLOCK_ADJTIME:
> + if (!capable(CAP_SYS_TIME))
> + return -EPERM;
> + if (copy_from_user(&ts, (void __user *)arg, sizeof(ts)))
> + err = -EFAULT;
> + else
> + err = ops->adjtime(priv, &ts);
> + break;
> +
> + case PTP_CLOCK_GETTIME:
> + err = ops->gettime(priv, &ts);
> + if (err)
> + break;
> + err = copy_to_user((void __user *)arg, &ts, sizeof(ts));
> + break;
> +
> + case PTP_CLOCK_SETTIME:
> + if (!capable(CAP_SYS_TIME))
> + return -EPERM;
> + if (copy_from_user(&ts, (void __user *)arg, sizeof(ts)))
> + err = -EFAULT;
> + else
> + err = ops->settime(priv, &ts);
> + break;
> +
> + case PTP_CLOCK_GETCAPS:
> + memset(&caps, 0, sizeof(caps));
> + caps.max_adj = ptp->info->max_adj;
> + caps.n_alarm = ptp->info->n_alarm;
> + caps.n_ext_ts = ptp->info->n_ext_ts;
> + caps.n_per_out = ptp->info->n_per_out;
> + caps.pps = ptp->info->pps;
> + err = copy_to_user((void __user *)arg, &caps, sizeof(caps));
> + break;
> +
> + case PTP_CLOCK_GETTIMER:
> + if (copy_from_user(&timer, (void __user *)arg, sizeof(timer))) {
> + err = -EFAULT;
> + break;
> + }
> + index = timer.alarm_index;
> + if (index < 0 || index >= ptp->info->n_alarm) {
> + err = -EINVAL;
> + break;
> + }
> + err = ops->gettimer(priv, index, &timer.tsp);
> + if (err)
> + break;
> + err = copy_to_user((void __user *)arg, &timer, sizeof(timer));
> + break;
> +
> + case PTP_CLOCK_SETTIMER:
> + if (copy_from_user(&timer, (void __user *)arg, sizeof(timer))) {
> + err = -EFAULT;
> + break;
> + }
> + index = timer.alarm_index;
> + if (index < 0 || index >= ptp->info->n_alarm) {
> + err = -EINVAL;
> + break;
> + }
> + if (!valid_signal(timer.signum))
> + return -EINVAL;
> + flags = timer.flags;
> + if (flags & (flags != TIMER_ABSTIME)) {
> + err = -EINVAL;
> + break;
> + }
> + if (mutex_lock_interruptible(&ptp->alarm_mux))
> + return -ERESTARTSYS;
> +
> + if (ptp->alarm[index].pid)
> + put_pid(ptp->alarm[index].pid);
> +
> + ptp->alarm[index].pid = get_pid(task_pid(current));
> + ptp->alarm[index].sig = timer.signum;
> + err = ops->settimer(priv, index, flags, &timer.tsp);
> +
> + mutex_unlock(&ptp->alarm_mux);
> + break;
> +
> + case PTP_FEATURE_REQUEST:
> + if (copy_from_user(&req, (void __user *)arg, sizeof(req))) {
> + err = -EFAULT;
> + break;
> + }
> + switch (req.type) {
> + case PTP_REQUEST_EXTTS:
> + case PTP_REQUEST_PEROUT:
> + break;
> + case PTP_REQUEST_PPS:
> + if (!capable(CAP_SYS_TIME))
> + return -EPERM;
> + break;
> + default:
> + err = -EINVAL;
> + break;
> + }
> + if (err)
> + break;
> + err = ops->enable(priv, &req,
> + req.flags & PTP_ENABLE_FEATURE ? 1 : 0);
> + break;
> +
> + default:
> + err = -ENOTTY;
> + break;
> + }
> + return err;
> +}
> +
> +static int ptp_open(struct inode *inode, struct file *fp)
> +{
> + struct ptp_clock *ptp;
> + ptp = container_of(inode->i_cdev, struct ptp_clock, cdev);
> +
> + fp->private_data = ptp;
> +
> + return 0;
> +}
> +
> +static unsigned int ptp_poll(struct file *fp, poll_table *wait)
> +{
> + struct ptp_clock *ptp = fp->private_data;
> +
> + poll_wait(fp, &ptp->tsev_wq, wait);
> +
> + return queue_cnt(&ptp->tsevq) ? POLLIN : 0;
> +}
> +
> +static ssize_t ptp_read(struct file *fp, char __user *buf,
> + size_t cnt, loff_t *off)
> +{
> + struct ptp_clock *ptp = fp->private_data;
> + struct timestamp_event_queue *queue = &ptp->tsevq;
> + struct ptp_extts_event *event;
> + size_t qcnt;
> +
> + if (mutex_lock_interruptible(&ptp->tsevq_mux))
> + return -ERESTARTSYS;
> +
> + cnt = cnt / sizeof(struct ptp_extts_event);
> +
> + if (wait_event_interruptible(ptp->tsev_wq,
> + (qcnt = queue_cnt(&ptp->tsevq)))) {
> + mutex_unlock(&ptp->tsevq_mux);
> + return -ERESTARTSYS;
> + }
> +
> + if (cnt > qcnt)
> + cnt = qcnt;
> +
> + event = &queue->buf[queue->head];
> +
> + if (copy_to_user(buf, event, cnt * sizeof(struct ptp_extts_event))) {
> + mutex_unlock(&ptp->tsevq_mux);
> + return -EFAULT;
> + }
> + queue->head = (queue->head + cnt) % PTP_MAX_TIMESTAMPS;
> +
> + mutex_unlock(&ptp->tsevq_mux);
> +
> + return cnt * sizeof(struct ptp_extts_event);
> +}
> +
> +static int ptp_release(struct inode *inode, struct file *fp)
> +{
> + struct ptp_clock *ptp;
> + struct itimerspec ts = {
> + {0, 0}, {0, 0}
> + };
> + int i;
> +
> + ptp = container_of(inode->i_cdev, struct ptp_clock, cdev);
> +
> + for (i = 0; i < ptp->info->n_alarm; i++) {
> + if (ptp->alarm[i].pid) {
> + ptp->info->settimer(ptp->info->priv, i, 0, &ts);
> + put_pid(ptp->alarm[i].pid);
> + ptp->alarm[i].pid = NULL;
> + }
> + }
> + return 0;
> +}
> +
> +static const struct file_operations ptp_fops = {
> + .owner = THIS_MODULE,
> + .ioctl = ptp_ioctl,
> + .open = ptp_open,
> + .poll = ptp_poll,
> + .read = ptp_read,
> + .release = ptp_release,
> +};
> +
> +/* sysfs */
> +
> +static ssize_t ptp_show_status(struct device *dev,
> + struct device_attribute *attr, char *buf)
> +{
> + struct ptp_clock *ptp = dev_get_drvdata(dev);
> + return sprintf(buf,
> + "maximum adjustment: %d\n"
> + "programmable alarms: %d\n"
> + "external timestamps: %d\n"
> + "periodic outputs: %d\n"
> + "has pps: %d\n"
> + "device index: %d\n",
> + ptp->info->max_adj,
> + ptp->info->n_alarm,
> + ptp->info->n_ext_ts,
> + ptp->info->n_per_out,
> + ptp->info->pps,
> + ptp->index);
> +}
Don't do this in a sysfs file. Use a debugfs file if you want to
export freeform data like this. sysfs files should contain either
only one value, or a simple list-of-same-type values. Formatted data
is completely out.
> +
> +struct device_attribute ptp_attrs[] = {
> + __ATTR(capabilities, S_IRUGO, ptp_show_status, NULL),
> + __ATTR_NULL,
> +};
> +
> +/* module operations */
> +
> +static void __exit ptp_exit(void)
> +{
> + class_destroy(ptp_class);
> + unregister_chrdev_region(ptp_devt, PTP_MAX_CLOCKS);
> +}
> +
> +static int __init ptp_init(void)
> +{
> + int err;
> +
> + INIT_LIST_HEAD(&clocks.list);
> +
> + ptp_class = class_create(THIS_MODULE, "ptp");
> + if (!ptp_class) {
> + printk(KERN_ERR "ptp: failed to allocate class\n");
> + return -ENOMEM;
> + }
> + ptp_class->dev_attrs = ptp_attrs;
> +
> + err = alloc_chrdev_region(&ptp_devt, 0, PTP_MAX_CLOCKS, "ptp");
> + if (err < 0) {
> + printk(KERN_ERR "ptp: failed to allocate char device region\n");
> + goto no_region;
> + }
> +
> + pr_info("PTP clock support registered\n");
> + return 0;
> +
> +no_region:
> + class_destroy(ptp_class);
> + return err;
> +}
> +
> +subsys_initcall(ptp_init);
> +module_exit(ptp_exit);
> +
> +MODULE_AUTHOR("Richard Cochran <richard.cochran@omicron.at>");
> +MODULE_DESCRIPTION("PTP clocks support");
> +MODULE_LICENSE("GPL");
> diff --git a/include/linux/Kbuild b/include/linux/Kbuild
> index 2fc8e14..9959fe4 100644
> --- a/include/linux/Kbuild
> +++ b/include/linux/Kbuild
> @@ -140,6 +140,7 @@ header-y += pkt_sched.h
> header-y += posix_types.h
> header-y += ppdev.h
> header-y += prctl.h
> +header-y += ptp_clock.h
> header-y += qnxtypes.h
> header-y += qnx4_fs.h
> header-y += radeonfb.h
> diff --git a/include/linux/ptp_clock.h b/include/linux/ptp_clock.h
> new file mode 100644
> index 0000000..5a509c5
> --- /dev/null
> +++ b/include/linux/ptp_clock.h
> @@ -0,0 +1,79 @@
> +/*
> + * PTP 1588 clock support - user space interface
> + *
> + * Copyright (C) 2010 OMICRON electronics GmbH
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _PTP_CLOCK_H_
> +#define _PTP_CLOCK_H_
> +
> +#include <linux/ioctl.h>
> +#include <linux/types.h>
> +
> +#define PTP_ENABLE_FEATURE (1<<0)
> +#define PTP_RISING_EDGE (1<<1)
> +#define PTP_FALLING_EDGE (1<<2)
> +
> +enum ptp_request_types {
> + PTP_REQUEST_EXTTS,
> + PTP_REQUEST_PEROUT,
> + PTP_REQUEST_PPS,
> +};
> +
> +struct ptp_clock_caps {
> + __s32 max_adj; /* Maximum frequency adjustment, parts per billon. */
> + int n_alarm; /* Number of programmable alarms. */
> + int n_ext_ts; /* Number of external time stamp channels. */
> + int n_per_out; /* Number of programmable periodic signals. */
> + int pps; /* Whether the clock supports a PPS callback. */
> +};
> +
> +struct ptp_clock_timer {
> + int alarm_index; /* Which alarm to query or configure. */
> + int signum; /* Requested signal. */
> + int flags; /* Zero or TIMER_ABSTIME, see TIMER_SETTIME(2) */
> + struct itimerspec tsp; /* See TIMER_SETTIME(2) */
> +};
> +
> +struct ptp_clock_request {
> + int type; /* One of the ptp_request_types enumeration values. */
> + int index; /* Which channel to configure. */
> + struct timespec ts; /* For period signals, the desired period. */
> + int flags; /* Bit field for PTP_ENABLE_FEATURE or other flags. */
> +};
> +
> +struct ptp_extts_event {
> + int index;
> + struct timespec ts;
> +};
> +
> +#define PTP_CLOCK_VERSION 0x00000001
> +
> +#define PTP_CLK_MAGIC '='
> +
> +#define PTP_CLOCK_APIVERS _IOR (PTP_CLK_MAGIC, 1, __u32)
> +#define PTP_CLOCK_ADJFREQ _IO (PTP_CLK_MAGIC, 2)
> +#define PTP_CLOCK_ADJTIME _IOW (PTP_CLK_MAGIC, 3, struct timespec)
> +#define PTP_CLOCK_GETTIME _IOR (PTP_CLK_MAGIC, 4, struct timespec)
> +#define PTP_CLOCK_SETTIME _IOW (PTP_CLK_MAGIC, 5, struct timespec)
> +
> +#define PTP_CLOCK_GETCAPS _IOR (PTP_CLK_MAGIC, 6, struct ptp_clock_caps)
> +#define PTP_CLOCK_GETTIMER _IOWR (PTP_CLK_MAGIC, 7, struct ptp_clock_timer)
> +#define PTP_CLOCK_SETTIMER _IOW (PTP_CLK_MAGIC, 8, struct ptp_clock_timer)
> +#define PTP_FEATURE_REQUEST _IOW (PTP_CLK_MAGIC, 9, struct ptp_clock_request)
> +
> +#endif
> diff --git a/include/linux/ptp_clock_kernel.h b/include/linux/ptp_clock_kernel.h
> new file mode 100644
> index 0000000..d6cc158
> --- /dev/null
> +++ b/include/linux/ptp_clock_kernel.h
> @@ -0,0 +1,137 @@
> +/*
> + * PTP 1588 clock support
> + *
> + * Copyright (C) 2010 OMICRON electronics GmbH
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _PTP_CLOCK_KERNEL_H_
> +#define _PTP_CLOCK_KERNEL_H_
> +
> +#include <linux/ptp_clock.h>
> +
> +/**
> + * struct ptp_clock_info - decribes a PTP hardware clock
> + *
> + * @owner: The clock driver should set to THIS_MODULE.
> + * @name: A short name to identify the clock.
> + * @max_adj: The maximum possible frequency adjustment, in parts per billon.
> + * @n_alarm: The number of programmable alarms.
> + * @n_ext_ts: The number of external time stamp channels.
> + * @n_per_out: The number of programmable periodic signals.
> + * @pps: Indicates whether the clock supports a PPS callback.
> + * @priv: Passed to the clock operations, for the driver's private use.
> + *
> + * clock operations
> + *
> + * @adjfreq: Adjusts the frequency of the hardware clock.
> + * parameter delta: Desired period change in parts per billion.
> + *
> + * @adjtime: Shifts the time of the hardware clock.
> + * parameter ts: Desired change in seconds and nanoseconds.
> + *
> + * @gettime: Reads the current time from the hardware clock.
> + * parameter ts: Holds the result.
> + *
> + * @settime: Set the current time on the hardware clock.
> + * parameter ts: Time value to set.
> + *
> + * @gettimer: Reads the time remaining from the given timer.
> + * parameter index: Which alarm to query.
> + * parameter ts: Holds the result.
> + *
> + * @settimer: Arms the given timer for periodic or one shot operation.
> + * parameter index: Which alarm to set.
> + * parameter abs: TIMER_ABSTIME, or zero for relative timer.
> + * parameter ts: Alarm time and period to set.
> + *
> + * @enable: Request driver to enable or disable an ancillary feature.
> + * parameter request: Desired resource to enable or disable.
> + * parameter on: Caller passes one to enable or zero to disable.
> + *
> + * The callbacks must all return zero on success, non-zero otherwise.
> + */
> +
> +struct ptp_clock_info {
> + struct module *owner;
> + char name[16];
> + s32 max_adj;
> + int n_alarm;
> + int n_ext_ts;
> + int n_per_out;
> + int pps;
> + void *priv;
> + int (*adjfreq)(void *priv, s32 delta);
> + int (*adjtime)(void *priv, struct timespec *ts);
> + int (*gettime)(void *priv, struct timespec *ts);
> + int (*settime)(void *priv, struct timespec *ts);
> + int (*gettimer)(void *priv, int index, struct itimerspec *ts);
> + int (*settimer)(void *priv, int index, int abs, struct itimerspec *ts);
> + int (*enable)(void *priv, struct ptp_clock_request *request, int on);
> +};
> +
> +struct ptp_clock;
> +
> +/**
> + * ptp_clock_register() - register a PTP hardware clock driver
> + *
> + * @info: Structure describing the new clock.
> + */
> +
> +extern struct ptp_clock *ptp_clock_register(struct ptp_clock_info *info);
> +
> +/**
> + * ptp_clock_unregister() - unregister a PTP hardware clock driver
> + *
> + * @ptp: The clock to remove from service.
> + */
> +
> +extern int ptp_clock_unregister(struct ptp_clock *ptp);
> +
> +
> +enum ptp_clock_events {
> + PTP_CLOCK_ALARM,
> + PTP_CLOCK_EXTTS,
> + PTP_CLOCK_PPS,
> +};
> +
> +/**
> + * struct ptp_clock_event - decribes a PTP hardware clock event
> + *
> + * @type: One of the ptp_clock_events enumeration values.
> + * @index: Identifies the source of the event.
> + * @timestamp: When the event occured.
> + */
> +
> +struct ptp_clock_event {
> + int type;
> + int index;
> + u64 timestamp;
> +};
> +
> +/**
> + * ptp_clock_event() - notify the PTP layer about an event
> + *
> + * This function should only be called from interrupt context.
> + *
> + * @ptp: The clock obtained from ptp_clock_register().
> + * @event: Message structure describing the event.
> + */
> +
> +extern void ptp_clock_event(struct ptp_clock *ptp,
> + struct ptp_clock_event *event);
> +
> +#endif
> --
> 1.6.3.3
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH 0/1] netfilter: netfilter fixes
From: David Miller @ 2010-06-15 18:59 UTC (permalink / raw)
To: kaber; +Cc: netfilter-devel, netdev
In-Reply-To: <1276613285-4959-1-git-send-email-kaber@trash.net>
From: kaber@trash.net
Date: Tue, 15 Jun 2010 16:48:04 +0200
> following is a single netfilter fix for IPVS from Sven Wegener, fixing a race
> condition that might result in an oops.
>
> Please apply or pull from:
>
> git://git.kernel.org/pub/scm/linux/kernel/git/kaber/nf-2.6.git master
Pulled, thanks Patrick.
^ permalink raw reply
* Re: [PATCH v2] tcp: unify tcp flag macros
From: David Miller @ 2010-06-15 18:56 UTC (permalink / raw)
To: xiaosuo; +Cc: kuznet, pekkas, jmorris, yoshfuji, kaber, netdev, netfilter-devel
In-Reply-To: <1276387303-25892-1-git-send-email-xiaosuo@gmail.com>
From: Changli Gao <xiaosuo@gmail.com>
Date: Sun, 13 Jun 2010 08:01:43 +0800
> unify tcp flag macros: TCPHDR_FIN, TCPHDR_SYN, TCPHDR_RST, TCPHDR_PSH,
> TCPHDR_ACK, TCPHDR_URG, TCPHDR_ECE and TCPHDR_CWR. TCBCB_FLAG_* are replaced
> with the corresponding TCPHDR_*.
>
> Signed-off-by: Changli Gao <xiaosuo@gmail.com>
Applied, thanks.
^ permalink raw reply
* [PATCH net-next 2/4] cnic: Refactor code in cnic_cm_process_kcqe().
From: Michael Chan @ 2010-06-15 18:57 UTC (permalink / raw)
To: davem; +Cc: netdev
In-Reply-To: <1276628223-27125-1-git-send-email-mchan@broadcom.com>
Move chip-specific code to the respective chip's ->close_conn() functions
for better code organization.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Eddie Wai <waie@broadcom.com>
---
drivers/net/cnic.c | 15 +++++++++------
1 files changed, 9 insertions(+), 6 deletions(-)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index b20e11c..48fdbce 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -3143,12 +3143,6 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
break;
case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
- if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
- cnic_cm_upcall(cp, csk, opcode);
- break;
- } else if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags))
- csk->state = opcode;
- /* fall through */
case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
case L4_KCQE_OPCODE_VALUE_RESET_COMP:
case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
@@ -3204,6 +3198,10 @@ static int cnic_cm_alloc_mem(struct cnic_dev *dev)
static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
{
+ if (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED) {
+ if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags))
+ csk->state = opcode;
+ }
if ((opcode == csk->state) ||
(opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED &&
csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)) {
@@ -3228,6 +3226,11 @@ static void cnic_close_bnx2_conn(struct cnic_sock *csk, u32 opcode)
struct cnic_dev *dev = csk->dev;
struct cnic_local *cp = dev->cnic_priv;
+ if (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED) {
+ cnic_cm_upcall(cp, csk, opcode);
+ return;
+ }
+
clear_bit(SK_F_CONNECT_START, &csk->flags);
cnic_close_conn(csk);
cnic_cm_upcall(cp, csk, opcode);
--
1.6.4.GIT
^ permalink raw reply related
* [PATCH net-next 4/4] cnic: Fix cnic_cm_abort() error handling.
From: Michael Chan @ 2010-06-15 18:57 UTC (permalink / raw)
To: davem; +Cc: netdev
In-Reply-To: <1276628223-27125-3-git-send-email-mchan@broadcom.com>
Fix the code that handles the error case when cnic_cm_abort() cannot
proceed normally. We cannot just set the csk->state and we must
go through cnic_ready_to_close() to handle all the conditions. We
also add error return code in cnic_cm_abort().
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Eddie Wai <waie@broadcom.com>
---
drivers/net/cnic.c | 29 ++++++++++++++++++-----------
1 files changed, 18 insertions(+), 11 deletions(-)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 11eeded..e5539f0 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -2996,7 +2996,7 @@ err_out:
static int cnic_cm_abort(struct cnic_sock *csk)
{
struct cnic_local *cp = csk->dev->cnic_priv;
- u32 opcode;
+ u32 opcode = L4_KCQE_OPCODE_VALUE_RESET_COMP;
if (!cnic_in_use(csk))
return -EINVAL;
@@ -3008,12 +3008,9 @@ static int cnic_cm_abort(struct cnic_sock *csk)
* connect was not successful.
*/
- csk->state = L4_KCQE_OPCODE_VALUE_RESET_COMP;
- if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
- opcode = csk->state;
- else
- opcode = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD;
cp->close_conn(csk, opcode);
+ if (csk->state != opcode)
+ return -EALREADY;
return 0;
}
@@ -3206,11 +3203,16 @@ static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
/* 1. If event opcode matches the expected event in csk->state
* 2. If the expected event is CLOSE_COMP, we accept any event
+ * 3. If the expected event is 0, meaning the connection was never
+ * never established, we accept the opcode from cm_abort.
*/
- if (opcode == csk->state ||
- csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) {
- if (!test_and_set_bit(SK_F_CLOSING, &csk->flags))
+ if (opcode == csk->state || csk->state == 0 ||
+ csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) {
+ if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) {
+ if (csk->state == 0)
+ csk->state = opcode;
return 1;
+ }
}
return 0;
}
@@ -3227,6 +3229,7 @@ static void cnic_close_bnx2_conn(struct cnic_sock *csk, u32 opcode)
clear_bit(SK_F_CONNECT_START, &csk->flags);
cnic_close_conn(csk);
+ csk->state = opcode;
cnic_cm_upcall(cp, csk, opcode);
}
@@ -3256,8 +3259,12 @@ static void cnic_close_bnx2x_conn(struct cnic_sock *csk, u32 opcode)
case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
case L4_KCQE_OPCODE_VALUE_RESET_COMP:
- if (cnic_ready_to_close(csk, opcode))
- cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE;
+ if (cnic_ready_to_close(csk, opcode)) {
+ if (test_bit(SK_F_PG_OFFLD_COMPLETE, &csk->flags))
+ cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE;
+ else
+ close_complete = 1;
+ }
break;
case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
cmd = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD;
--
1.6.4.GIT
^ permalink raw reply related
* [PATCH net-next 3/4] cnic: Refactor and fix cnic_ready_to_close().
From: Michael Chan @ 2010-06-15 18:57 UTC (permalink / raw)
To: davem; +Cc: netdev
In-Reply-To: <1276628223-27125-2-git-send-email-mchan@broadcom.com>
Combine RESET_RECEIVED and RESET_COMP logic and fix race condition
between these 2 events and cnic_cm_close(). In particular, we need
to (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) before we
update csk->state.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Eddie Wai <waie@broadcom.com>
---
drivers/net/cnic.c | 26 ++++++++++----------------
1 files changed, 10 insertions(+), 16 deletions(-)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 48fdbce..11eeded 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -3198,25 +3198,19 @@ static int cnic_cm_alloc_mem(struct cnic_dev *dev)
static int cnic_ready_to_close(struct cnic_sock *csk, u32 opcode)
{
- if (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED) {
- if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags))
- csk->state = opcode;
- }
- if ((opcode == csk->state) ||
- (opcode == L4_KCQE_OPCODE_VALUE_RESET_RECEIVED &&
- csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP)) {
- if (!test_and_set_bit(SK_F_CLOSING, &csk->flags))
- return 1;
+ if (test_and_clear_bit(SK_F_OFFLD_COMPLETE, &csk->flags)) {
+ /* Unsolicited RESET_COMP or RESET_RECEIVED */
+ opcode = L4_KCQE_OPCODE_VALUE_RESET_RECEIVED;
+ csk->state = opcode;
}
- /* 57710+ only workaround to handle unsolicited RESET_COMP
- * which will be treated like a RESET RCVD notification
- * which triggers the clean up procedure
+
+ /* 1. If event opcode matches the expected event in csk->state
+ * 2. If the expected event is CLOSE_COMP, we accept any event
*/
- else if (opcode == L4_KCQE_OPCODE_VALUE_RESET_COMP) {
- if (!test_and_set_bit(SK_F_CLOSING, &csk->flags)) {
- csk->state = L4_KCQE_OPCODE_VALUE_RESET_RECEIVED;
+ if (opcode == csk->state ||
+ csk->state == L4_KCQE_OPCODE_VALUE_CLOSE_COMP) {
+ if (!test_and_set_bit(SK_F_CLOSING, &csk->flags))
return 1;
- }
}
return 0;
}
--
1.6.4.GIT
^ permalink raw reply related
* [PATCH net-next 1/4] cnic: Return error code in cnic_cm_close() if unsuccessful.
From: Michael Chan @ 2010-06-15 18:57 UTC (permalink / raw)
To: davem; +Cc: netdev
So that bnx2i can handle the error condition immediately and not have to
wait for timeout.
Signed-off-by: Michael Chan <mchan@broadcom.com.
Signed-off-by: Eddie Wai <waie@broadcom.com>
---
drivers/net/cnic.c | 2 ++
1 files changed, 2 insertions(+), 0 deletions(-)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 908d89a..b20e11c 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -3026,6 +3026,8 @@ static int cnic_cm_close(struct cnic_sock *csk)
if (cnic_close_prep(csk)) {
csk->state = L4_KCQE_OPCODE_VALUE_CLOSE_COMP;
return cnic_cm_close_req(csk);
+ } else {
+ return -EALREADY;
}
return 0;
}
--
1.6.4.GIT
^ permalink raw reply related
* Re: [PATCH 12/12] ptp: Added a clock driver for the National Semiconductor PHYTER.
From: Grant Likely @ 2010-06-15 18:49 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev, devicetree-discuss, linuxppc-dev, linux-arm-kernel,
Krzysztof Halasa
In-Reply-To: <37f5015b186bdd51f8451ade042f90c8b39a5cc8.1276615626.git.richard.cochran@omicron.at>
On Tue, Jun 15, 2010 at 10:10 AM, Richard Cochran
<richardcochran@gmail.com> wrote:
> This patch adds support for the PTP clock found on the DP83640. Only the
> basic clock operations have been implemented.
>
> Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
> ---
> drivers/net/phy/Kconfig | 11 +++
> drivers/net/phy/dp83640.c | 158 ++++++++++++++++++++++++++++++++++++++++++++-
> 2 files changed, 168 insertions(+), 1 deletions(-)
>
> diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
> index 430cab1..507c68a 100644
> --- a/drivers/net/phy/Kconfig
> +++ b/drivers/net/phy/Kconfig
> @@ -79,9 +79,20 @@ config NATIONAL_PHY
>
> config DP83640_PHY
> tristate "Driver for the National Semiconductor DP83640 PHYTER"
> + depends on PTP_1588_CLOCK
> + depends on NETWORK_PHY_TIMESTAMPING
Won't this break things for existing DP83640 users?
> ---help---
> Supports the DP83640 PHYTER with IEEE 1588 features.
>
> + This driver adds support for using the DP83640 as a PTP
> + clock. This clock is only useful if your PTP programs are
> + getting hardware time stamps on the PTP Ethernet packets
> + using the SO_TIMESTAMPING API.
> +
> + In order for this to work, your MAC driver must also
> + implement the the skb_tx_timetamp() and skb_rx_timetamp()
> + functions.
> +
> config STE10XP
> depends on PHYLIB
> tristate "Driver for STMicroelectronics STe10Xp PHYs"
> diff --git a/drivers/net/phy/dp83640.c b/drivers/net/phy/dp83640.c
> index a3217ea..21eadc3 100644
> --- a/drivers/net/phy/dp83640.c
> +++ b/drivers/net/phy/dp83640.c
> @@ -26,6 +26,7 @@
> #include <linux/netdevice.h>
> #include <linux/phy.h>
> #include <linux/ptp_classify.h>
> +#include <linux/ptp_clock_kernel.h>
>
> #include "dp83640_reg.h"
>
> @@ -45,10 +46,13 @@ struct rxts {
> };
>
> struct dp83640_private {
> + struct phy_device *phydev;
> int hwts_tx_en;
> int hwts_rx_en;
> int layer;
> int version;
> + /* protects PTP_TDR register from concurrent access */
> + spinlock_t ptp_tdr_lock;
> /* protects extended registers from concurrent access */
> spinlock_t extreg_lock;
> int page;
> @@ -60,6 +64,9 @@ struct dp83640_private {
>
> /* globals */
>
> +static struct ptp_clock *dp83640_clock;
> +DEFINE_SPINLOCK(clock_lock); /* protects the one and only dp83640_clock */
Why only one? Is it not possible to have 2 of these PHYs in a system?
> +
> static struct sock_filter ptp_filter[] = {
> PTP_FILTER
> };
> @@ -99,6 +106,129 @@ static void ext_write(struct phy_device *phydev, int page, u32 regnum, u16 val)
> spin_unlock(&dp83640->extreg_lock);
> }
>
> +static int tdr_write(struct dp83640_private *dp83640,
> + struct timespec *ts, u16 cmd)
> +{
> + struct phy_device *phydev = dp83640->phydev;
> +
> + spin_lock(&dp83640->ptp_tdr_lock);
> +
> + ext_write(phydev, PAGE4, PTP_TDR, ts->tv_nsec & 0xffff);/* ns[15:0] */
> + ext_write(phydev, PAGE4, PTP_TDR, ts->tv_nsec >> 16); /* ns[31:16] */
> + ext_write(phydev, PAGE4, PTP_TDR, ts->tv_sec & 0xffff); /* sec[15:0] */
> + ext_write(phydev, PAGE4, PTP_TDR, ts->tv_sec >> 16); /* sec[31:16] */
> +
> + ext_write(phydev, PAGE4, PTP_CTL, cmd);
> +
> + spin_unlock(&dp83640->ptp_tdr_lock);
> +
> + return 0;
> +}
> +
> +/* ptp clock methods */
> +
> +static int ptp_dp83640_adjfreq(void *priv, s32 ppb)
> +{
> + struct dp83640_private *dp83640 = priv;
> + struct phy_device *phydev = dp83640->phydev;
> + u64 rate;
> + int neg_adj = 0;
> + u16 hi, lo;
> +
> + if (!ppb)
> + return 0;
> +
> + if (ppb < 0) {
> + neg_adj = 1;
> + ppb = -ppb;
> + }
> + rate = ppb;
> + rate <<= 26;
> + rate = div_u64(rate, 1953125);
> +
> + hi = (rate >> 16) & PTP_RATE_HI_MASK;
> + if (neg_adj)
> + hi |= PTP_RATE_DIR;
> +
> + lo = rate & 0xffff;
> +
> + ext_write(phydev, PAGE4, PTP_RATEH, hi);
> + ext_write(phydev, PAGE4, PTP_RATEL, lo);
> +
> + return 0;
> +}
> +
> +static int ptp_dp83640_adjtime(void *priv, struct timespec *ts)
> +{
> + return tdr_write(priv, ts, PTP_STEP_CLK);
> +}
> +
> +static int ptp_dp83640_gettime(void *priv, struct timespec *ts)
> +{
> + struct dp83640_private *dp83640 = priv;
> + struct phy_device *phydev = dp83640->phydev;
> + unsigned int val[4];
> +
> + spin_lock(&dp83640->ptp_tdr_lock);
> +
> + ext_write(phydev, PAGE4, PTP_CTL, PTP_RD_CLK);
> +
> + val[0] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[15:0] */
> + val[1] = ext_read(phydev, PAGE4, PTP_TDR); /* ns[31:16] */
> + val[2] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[15:0] */
> + val[3] = ext_read(phydev, PAGE4, PTP_TDR); /* sec[31:16] */
> +
> + spin_unlock(&dp83640->ptp_tdr_lock);
> +
> + ts->tv_nsec = val[0] | (val[1] << 16);
> + ts->tv_sec = val[2] | (val[3] << 16);
> +
> + return 0;
> +}
> +
> +static int ptp_dp83640_settime(void *priv, struct timespec *ts)
> +{
> + return tdr_write(priv, ts, PTP_LOAD_CLK);
> +}
> +
> +static int ptp_dp83640_gettimer(void *priv, int index, struct itimerspec *ts)
> +{
> + /* We do not (yet) offer any ancillary features. */
> + return -EOPNOTSUPP;
> +}
> +
> +static int ptp_dp83640_settimer(void *p, int i, int abs, struct itimerspec *ts)
> +{
> + /* We do not (yet) offer any ancillary features. */
> + return -EOPNOTSUPP;
> +}
> +
> +static int ptp_dp83640_enable(void *priv, struct ptp_clock_request *rq, int on)
> +{
> + /* We do not (yet) offer any ancillary features. */
> + return -EOPNOTSUPP;
> +}
> +
> +static struct ptp_clock_info ptp_dp83640_caps = {
> + .owner = THIS_MODULE,
> + .name = "dp83640 timer",
> + .max_adj = 1953124,
> + .n_alarm = 0,
> + .n_ext_ts = 0,
> + .n_per_out = 0,
> + .pps = 0,
> + .priv = NULL,
ditto here, can leave the 0s and nulls out.
> + .adjfreq = ptp_dp83640_adjfreq,
> + .adjtime = ptp_dp83640_adjtime,
> + .gettime = ptp_dp83640_gettime,
> + .settime = ptp_dp83640_settime,
> + .gettimer = ptp_dp83640_gettimer,
> + .settimer = ptp_dp83640_settimer,
> + .enable = ptp_dp83640_enable,
> +};
> +
> +/* time stamping methods */
> +
> static int expired(struct rxts *rxts)
> {
> return time_after(jiffies, rxts->tmo);
> @@ -144,6 +274,7 @@ static int match(struct sk_buff *skb, unsigned int type, struct rxts *rxts)
> static int dp83640_probe(struct phy_device *phydev)
> {
> struct dp83640_private *dp83640;
> + unsigned long flags;
> int i;
>
> if (sk_chk_filter(ptp_filter, ARRAY_SIZE(ptp_filter))) {
> @@ -155,8 +286,9 @@ static int dp83640_probe(struct phy_device *phydev)
> if (!dp83640)
> return -ENOMEM;
>
> + dp83640->phydev = phydev;
> + spin_lock_init(&dp83640->ptp_tdr_lock);
> spin_lock_init(&dp83640->extreg_lock);
> -
> INIT_LIST_HEAD(&dp83640->rxts);
> INIT_LIST_HEAD(&dp83640->pool);
>
> @@ -165,12 +297,36 @@ static int dp83640_probe(struct phy_device *phydev)
>
> phydev->priv = dp83640;
>
> + spin_lock_irqsave(&clock_lock, flags);
> +
> + if (!dp83640_clock) {
> + ptp_dp83640_caps.priv = dp83640;
> + dp83640_clock = ptp_clock_register(&ptp_dp83640_caps);
> + if (IS_ERR(dp83640_clock)) {
> + spin_unlock_irqrestore(&clock_lock, flags);
> + kfree(dp83640);
> + return PTR_ERR(dp83640_clock);
> + }
> + }
> + spin_unlock_irqrestore(&clock_lock, flags);
> +
> return 0;
> }
>
> static void dp83640_remove(struct phy_device *phydev)
> {
> struct dp83640_private *dp83640 = phydev->priv;
> + unsigned long flags;
> +
> + spin_lock_irqsave(&clock_lock, flags);
> +
> + if (ptp_dp83640_caps.priv == dp83640) {
> + ptp_clock_unregister(dp83640_clock);
> + dp83640_clock = NULL;
> + ptp_dp83640_caps.priv = NULL;
> + }
> + spin_unlock_irqrestore(&clock_lock, flags);
> +
> kfree(dp83640);
> }
>
> --
> 1.6.3.3
>
>
> _______________________________________________
> linux-arm-kernel mailing list
> linux-arm-kernel@lists.infradead.org
> http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
>
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [PATCH net-next-2.6 3/3 v3] bridge: use rx_handler_data pointer to store net_bridge_port pointer
From: David Miller @ 2010-06-15 18:50 UTC (permalink / raw)
To: jpirko; +Cc: netdev, shemminger, kaber, eric.dumazet
In-Reply-To: <20100615165043.GA2623@psychotron.redhat.com>
From: Jiri Pirko <jpirko@redhat.com>
Date: Tue, 15 Jun 2010 18:50:45 +0200
> Register net_bridge_port pointer as rx_handler data pointer. As br_port is
> removed from struct net_device, another netdev priv_flag is added to indicate
> the device serves as a bridge port. Also rcuized pointers are now correctly
> dereferenced in br_fdb.c and in netfilter parts.
>
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Applied.
^ permalink raw reply
* Re: [PATCH net-next-2.6 2/3] macvlan: use rx_handler_data pointer to store macvlan_port pointer V2
From: David Miller @ 2010-06-15 18:50 UTC (permalink / raw)
To: jpirko; +Cc: netdev, shemminger, kaber, eric.dumazet
In-Reply-To: <20100615132756.GA3797@psychotron.lab.eng.brq.redhat.com>
From: Jiri Pirko <jpirko@redhat.com>
Date: Tue, 15 Jun 2010 15:27:57 +0200
> Register macvlan_port pointer as rx_handler data pointer. As macvlan_port is
> removed from struct net_device, another netdev priv_flag is added to indicate
> the device serves as a macvlan port.
>
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
> Acked-by: Patrick McHardy <kaber@trash.net>
Applied.
^ permalink raw reply
* Re: [PATCH net-next-2.6 1/3] net: add rx_handler data pointer
From: David Miller @ 2010-06-15 18:49 UTC (permalink / raw)
To: jpirko; +Cc: netdev, shemminger, kaber, eric.dumazet
In-Reply-To: <20100610133458.GD2618@psychotron.lab.eng.brq.redhat.com>
From: Jiri Pirko <jpirko@redhat.com>
Date: Thu, 10 Jun 2010 15:34:59 +0200
> Add possibility to register rx_handler data pointer along with a rx_handler.
>
> Signed-off-by: Jiri Pirko <jpirko@redhat.com>
Applied.
^ permalink raw reply
* Re: [PATCH 11/12] ptp: Added a clock driver for the IXP46x.
From: Grant Likely @ 2010-06-15 18:41 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
devicetree-discuss-uLR06cmDAlY/bJ5BZ2RsiQ,
linuxppc-dev-uLR06cmDAlY/bJ5BZ2RsiQ,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
Krzysztof Halasa
In-Reply-To: <0c03ef3e283c6b3ef58feaf1f77ccb0fd605010b.1276615626.git.richard.cochran-3mrvs1K0uXizZXS1Dc/lvw@public.gmane.org>
On Tue, Jun 15, 2010 at 10:10 AM, Richard Cochran
<richardcochran-Re5JQEeQqe8AvxtiuMwx3w@public.gmane.org> wrote:
> This patch adds a driver for the hardware time stamping unit found on the
> IXP465. Only the basic clock operations are implemented.
>
> Signed-off-by: Richard Cochran <richard.cochran-3mrvs1K0uXizZXS1Dc/lvw@public.gmane.org>
Hi Richard,
Comments below...
> ---
> arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h | 67 +++++++
> drivers/net/arm/ixp4xx_eth.c | 194 +++++++++++++++++++++
> drivers/ptp/Kconfig | 13 ++
> drivers/ptp/Makefile | 1 +
> drivers/ptp/ptp_ixp46x.c | 231 +++++++++++++++++++++++++
> 5 files changed, 506 insertions(+), 0 deletions(-)
> create mode 100644 arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h
> create mode 100644 drivers/ptp/ptp_ixp46x.c
>
> diff --git a/arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h b/arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h
> new file mode 100644
> index 0000000..7fb02b6
> --- /dev/null
> +++ b/arch/arm/mach-ixp4xx/include/mach/ixp46x_ts.h
> @@ -0,0 +1,67 @@
> +/*
> + * PTP 1588 clock using the IXP46X
> + *
> + * Copyright (C) 2010 OMICRON electronics GmbH
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +
> +#ifndef _IXP46X_TS_H_
> +#define _IXP46X_TS_H_
> +
> +#define DEFAULT_ADDEND 0xF0000029
> +#define TICKS_NS_SHIFT 4
> +
> +struct ixp46x_channel_ctl {
> + u32 Ch_Control; /* 0x40 Time Synchronization Channel Control */
> + u32 Ch_Event; /* 0x44 Time Synchronization Channel Event */
> + u32 TxSnapLo; /* 0x48 Transmit Snapshot Low Register */
> + u32 TxSnapHi; /* 0x4C Transmit Snapshot High Register */
> + u32 RxSnapLo; /* 0x50 Receive Snapshot Low Register */
> + u32 RxSnapHi; /* 0x54 Receive Snapshot High Register */
> + u32 SrcUUIDLo; /* 0x58 Source UUID0 Low Register */
> + u32 SrcUUIDHi; /* 0x5C Sequence Identifier/Source UUID0 High */
> +};
Nitpick. We use all lower case names for structures in Linux.
> +
> +struct ixp46x_ts_regs {
> + u32 Control; /* 0x00 Time Sync Control Register */
> + u32 Event; /* 0x04 Time Sync Event Register */
> + u32 Addend; /* 0x08 Time Sync Addend Register */
> + u32 Accum; /* 0x0C Time Sync Accumulator Register */
> + u32 Test; /* 0x10 Time Sync Test Register */
> + u32 Unused; /* 0x14 */
> + u32 RSysTime_Lo; /* 0x18 RawSystemTime_Low Register */
> + u32 RSysTimeHi; /* 0x1C RawSystemTime_High Register */
> + u32 SysTimeLo; /* 0x20 SystemTime_Low Register */
> + u32 SysTimeHi; /* 0x24 SystemTime_High Register */
> + u32 TrgtLo; /* 0x28 TargetTime_Low Register */
> + u32 TrgtHi; /* 0x2C TargetTime_High Register */
> + u32 ASMSLo; /* 0x30 Auxiliary Slave Mode Snapshot Low */
> + u32 ASMSHi; /* 0x34 Auxiliary Slave Mode Snapshot High */
> + u32 AMMSLo; /* 0x38 Auxiliary Master Mode Snapshot Low */
> + u32 AMMSHi; /* 0x3C Auxiliary Master Mode Snapshot High */
> +
> + struct ixp46x_channel_ctl channel[3];
> +};
> +
> +/* 0x40 Time Synchronization Channel Control Register Bits */
> +#define MASTER_MODE (1<<0)
> +#define TIMESTAMP_ALL (1<<1)
> +
> +/* 0x44 Time Synchronization Channel Event Register Bits */
> +#define TX_SNAPSHOT_LOCKED (1<<0)
> +#define RX_SNAPSHOT_LOCKED (1<<1)
> +
> +#endif
> diff --git a/drivers/net/arm/ixp4xx_eth.c b/drivers/net/arm/ixp4xx_eth.c
> index 4f1cc71..2201960 100644
> --- a/drivers/net/arm/ixp4xx_eth.c
> +++ b/drivers/net/arm/ixp4xx_eth.c
> @@ -30,9 +30,12 @@
> #include <linux/etherdevice.h>
> #include <linux/io.h>
> #include <linux/kernel.h>
> +#include <linux/net_tstamp.h>
> #include <linux/phy.h>
> #include <linux/platform_device.h>
> +#include <linux/ptp_classify.h>
> #include <linux/slab.h>
> +#include <mach/ixp46x_ts.h>
> #include <mach/npe.h>
> #include <mach/qmgr.h>
>
> @@ -67,6 +70,14 @@
> #define RXFREE_QUEUE(port_id) (NPE_ID(port_id) + 26)
> #define TXDONE_QUEUE 31
>
> +#define PTP_SLAVE_MODE 1
> +#define PTP_MASTER_MODE 2
> +#define PORT2CHANNEL(p) 1
> +/*
> + * PHYSICAL_ID(p->id) ?
> + * TODO - Figure out correct mapping.
> + */
> +
> /* TX Control Registers */
> #define TX_CNTRL0_TX_EN 0x01
> #define TX_CNTRL0_HALFDUPLEX 0x02
> @@ -171,6 +182,8 @@ struct port {
> int id; /* logical port ID */
> int speed, duplex;
> u8 firmware[4];
> + int hwts_tx_en;
> + int hwts_rx_en;
> };
>
> /* NPE message structure */
> @@ -246,6 +259,170 @@ static int ports_open;
> static struct port *npe_port_tab[MAX_NPES];
> static struct dma_pool *dma_pool;
>
> +static struct sock_filter ptp_filter[] = {
> + PTP_FILTER
> +};
> +
> +static int match(struct sk_buff *skb, u16 uid_hi, u32 uid_lo, u16 seq)
> +{
> + unsigned int type;
> + u16 *hi, *id;
> + u8 *lo, *data = skb->data;
> +
> + type = sk_run_filter(skb, ptp_filter, ARRAY_SIZE(ptp_filter));
> +
> + if (PTP_CLASS_V1_IPV4 == type) {
> +
> + id = (u16 *)(data + 42 + 30);
> + hi = (u16 *)(data + 42 + 22);
> + lo = data + 42 + 24;
> +
> + return (uid_hi == *hi &&
> + 0 == memcmp(&uid_lo, lo, sizeof(uid_lo)) &&
> + seq == *id);
> + }
> +
> + return 0;
> +}
> +
> +static void do_rx_timestamp(struct port *port, struct sk_buff *skb)
> +{
> + struct skb_shared_hwtstamps *shhwtstamps;
> + struct ixp46x_ts_regs *regs;
> + u64 ns;
> + u32 ch, hi, lo, val;
> + u16 uid, seq;
> +
> + if (!port->hwts_rx_en)
> + return;
> +
> + ch = PORT2CHANNEL(port);
> +
> + regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
> +
> + val = __raw_readl(®s->channel[ch].Ch_Event);
> +
> + if (!(val & RX_SNAPSHOT_LOCKED))
> + return;
> +
> + lo = __raw_readl(®s->channel[ch].SrcUUIDLo);
> + hi = __raw_readl(®s->channel[ch].SrcUUIDHi);
> +
> + uid = hi & 0xffff;
> + seq = (hi >> 16) & 0xffff;
> +
> + if (!match(skb, htons(uid), htonl(lo), htons(seq)))
> + goto out;
> +
> + lo = __raw_readl(®s->channel[ch].RxSnapLo);
> + hi = __raw_readl(®s->channel[ch].RxSnapHi);
> + ns = ((u64) hi) << 32;
> + ns |= lo;
> + ns <<= TICKS_NS_SHIFT;
> +
> + shhwtstamps = skb_hwtstamps(skb);
> + memset(shhwtstamps, 0, sizeof(*shhwtstamps));
> + shhwtstamps->hwtstamp = ns_to_ktime(ns);
> +out:
> + __raw_writel(RX_SNAPSHOT_LOCKED, ®s->channel[ch].Ch_Event);
> +}
> +
> +static void do_tx_timestamp(struct port *port, struct sk_buff *skb)
> +{
> +#ifdef __ARMEB__
> + struct skb_shared_hwtstamps shhwtstamps;
> + struct ixp46x_ts_regs *regs;
> + union skb_shared_tx *shtx;
> + u64 ns;
> + u32 ch, cnt, hi, lo, val;
> +
> + shtx = skb_tx(skb);
> +
> + if (!shtx->in_progress)
> + return;
> +
> + ch = PORT2CHANNEL(port);
> +
> + regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
> +
> + /*
> + * This really stinks, but we have to poll for the Tx time stamp.
> + * Usually, the time stamp is ready after 4 to 6 microseconds.
> + */
> + for (cnt = 0; cnt < 100; cnt++) {
> + val = __raw_readl(®s->channel[ch].Ch_Event);
> + if (val & TX_SNAPSHOT_LOCKED)
> + break;
> + udelay(1);
You want to get stuff as fast as possible, but there is a udelay()
that just chews up CPU time. Would cpu_relax() be sufficient with a
time-based exit condition in the loop?
> + }
> + if (!(val & TX_SNAPSHOT_LOCKED)) {
> + shtx->in_progress = 0;
> + return;
> + }
> +
> + lo = __raw_readl(®s->channel[ch].TxSnapLo);
> + hi = __raw_readl(®s->channel[ch].TxSnapHi);
> + ns = ((u64) hi) << 32;
> + ns |= lo;
> + ns <<= TICKS_NS_SHIFT;
> +
> + memset(&shhwtstamps, 0, sizeof(shhwtstamps));
> + shhwtstamps.hwtstamp = ns_to_ktime(ns);
> + skb_tstamp_tx(skb, &shhwtstamps);
> +
> + __raw_writel(TX_SNAPSHOT_LOCKED, ®s->channel[ch].Ch_Event);
> +#endif
> +}
> +
> +static int hwtstamp_ioctl(struct net_device *netdev, struct ifreq *ifr, int cmd)
> +{
> + struct hwtstamp_config cfg;
> + struct ixp46x_ts_regs *regs;
> + struct port *port = netdev_priv(netdev);
> + int ch;
> +
> + if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg)))
> + return -EFAULT;
> +
> + if (cfg.flags) /* reserved for future extensions */
> + return -EINVAL;
> +
> + ch = PORT2CHANNEL(port);
> + regs = (struct ixp46x_ts_regs __iomem *) IXP4XX_TIMESYNC_BASE_VIRT;
> +
> + switch (cfg.tx_type) {
> + case HWTSTAMP_TX_OFF:
> + port->hwts_tx_en = 0;
> + break;
> + case HWTSTAMP_TX_ON:
> + port->hwts_tx_en = 1;
> + break;
> + default:
> + return -ERANGE;
> + }
> +
> + switch (cfg.rx_filter) {
> + case HWTSTAMP_FILTER_NONE:
> + port->hwts_rx_en = 0;
> + break;
> + case HWTSTAMP_FILTER_PTP_V1_L4_SYNC:
> + port->hwts_rx_en = PTP_SLAVE_MODE;
> + __raw_writel(0, ®s->channel[ch].Ch_Control);
> + break;
> + case HWTSTAMP_FILTER_PTP_V1_L4_DELAY_REQ:
> + port->hwts_rx_en = PTP_MASTER_MODE;
> + __raw_writel(MASTER_MODE, ®s->channel[ch].Ch_Control);
> + break;
> + default:
> + return -ERANGE;
> + }
> +
> + /* Clear out any old time stamps. */
> + __raw_writel(TX_SNAPSHOT_LOCKED | RX_SNAPSHOT_LOCKED,
> + ®s->channel[ch].Ch_Event);
> +
> + return copy_to_user(ifr->ifr_data, &cfg, sizeof(cfg)) ? -EFAULT : 0;
> +}
>
> static int ixp4xx_mdio_cmd(struct mii_bus *bus, int phy_id, int location,
> int write, u16 cmd)
> @@ -573,6 +750,7 @@ static int eth_poll(struct napi_struct *napi, int budget)
>
> debug_pkt(dev, "eth_poll", skb->data, skb->len);
>
> + do_rx_timestamp(port, skb);
> skb->protocol = eth_type_trans(skb, dev);
> dev->stats.rx_packets++;
> dev->stats.rx_bytes += skb->len;
> @@ -652,6 +830,7 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
> void *mem;
> u32 phys;
> struct desc *desc;
> + union skb_shared_tx *shtx;
>
> #if DEBUG_TX
> printk(KERN_DEBUG "%s: eth_xmit\n", dev->name);
> @@ -665,6 +844,10 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
>
> debug_pkt(dev, "eth_xmit", skb->data, skb->len);
>
> + shtx = skb_tx(skb);
> + if (unlikely(shtx->hardware && port->hwts_tx_en))
> + shtx->in_progress = 1;
> +
> len = skb->len;
> #ifdef __ARMEB__
> offset = 0; /* no need to keep alignment */
> @@ -728,6 +911,9 @@ static int eth_xmit(struct sk_buff *skb, struct net_device *dev)
> #if DEBUG_TX
> printk(KERN_DEBUG "%s: eth_xmit end\n", dev->name);
> #endif
> +
> + do_tx_timestamp(port, skb);
> +
> return NETDEV_TX_OK;
> }
>
> @@ -783,6 +969,9 @@ static int eth_ioctl(struct net_device *dev, struct ifreq *req, int cmd)
> if (!netif_running(dev))
> return -EINVAL;
>
> + if (cpu_is_ixp46x() && cmd == SIOCSHWTSTAMP)
> + return hwtstamp_ioctl(dev, req, cmd);
> +
> return phy_mii_ioctl(port->phydev, req, cmd);
> }
>
> @@ -1171,6 +1360,11 @@ static int __devinit eth_init_one(struct platform_device *pdev)
> char phy_id[MII_BUS_ID_SIZE + 3];
> int err;
>
> + if (sk_chk_filter(ptp_filter, ARRAY_SIZE(ptp_filter))) {
> + pr_err("ixp4xx_eth: bad ptp filter\n");
> + return -EINVAL;
> + }
> +
> if (!(dev = alloc_etherdev(sizeof(struct port))))
> return -ENOMEM;
>
> diff --git a/drivers/ptp/Kconfig b/drivers/ptp/Kconfig
> index 3b7bd73..9fb35f6 100644
> --- a/drivers/ptp/Kconfig
> +++ b/drivers/ptp/Kconfig
> @@ -48,4 +48,17 @@ config PTP_1588_CLOCK_GIANFAR
> To compile this driver as a module, choose M here: the module
> will be called gianfar_ptp.
>
> +config PTP_1588_CLOCK_IXP46X
> + tristate "Intel IXP46x as PTP clock"
> + depends on PTP_1588_CLOCK
> + depends on IXP4XX_ETH
> + help
> + This driver adds support for using the IXP46X as a PTP
> + clock. This clock is only useful if your PTP programs are
> + getting hardware time stamps on the PTP Ethernet packets
> + using the SO_TIMESTAMPING API.
> +
> + To compile this driver as a module, choose M here: the module
> + will be called ptp_ixp46x.
> +
> endmenu
> diff --git a/drivers/ptp/Makefile b/drivers/ptp/Makefile
> index 1651d52..5018f58 100644
> --- a/drivers/ptp/Makefile
> +++ b/drivers/ptp/Makefile
> @@ -4,3 +4,4 @@
>
> obj-$(CONFIG_PTP_1588_CLOCK) += ptp_clock.o
> obj-$(CONFIG_PTP_1588_CLOCK_LINUX) += ptp_linux.o
> +obj-$(CONFIG_PTP_1588_CLOCK_IXP46X) += ptp_ixp46x.o
> diff --git a/drivers/ptp/ptp_ixp46x.c b/drivers/ptp/ptp_ixp46x.c
> new file mode 100644
> index 0000000..22c5bc3
> --- /dev/null
> +++ b/drivers/ptp/ptp_ixp46x.c
> @@ -0,0 +1,231 @@
> +/*
> + * PTP 1588 clock using the IXP46X
> + *
> + * Copyright (C) 2010 OMICRON electronics GmbH
> + *
> + * This program is free software; you can redistribute it and/or modify
> + * it under the terms of the GNU General Public License as published by
> + * the Free Software Foundation; either version 2 of the License, or
> + * (at your option) any later version.
> + *
> + * This program is distributed in the hope that it will be useful,
> + * but WITHOUT ANY WARRANTY; without even the implied warranty of
> + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> + * GNU General Public License for more details.
> + *
> + * You should have received a copy of the GNU General Public License
> + * along with this program; if not, write to the Free Software
> + * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
> + */
> +#include <linux/device.h>
> +#include <linux/err.h>
> +#include <linux/init.h>
> +#include <linux/io.h>
> +#include <linux/kernel.h>
> +#include <linux/module.h>
> +
> +#include <linux/ptp_clock_kernel.h>
> +#include <mach/ixp46x_ts.h>
> +
> +DEFINE_SPINLOCK(register_lock);
> +
> +/*
> + * Register access functions
> + */
> +
> +static inline u32 ixp_read(volatile unsigned __iomem *addr)
> +{
> + u32 val;
> + val = __raw_readl(addr);
> + return val;
> +}
return __raw_readl(addr) perhaps?
> +
> +static inline void ixp_write(volatile unsigned __iomem *addr, u32 val)
> +{
> + __raw_writel(val, addr);
> +}
> +
> +static u64 sys_time_read(struct ixp46x_ts_regs *regs)
> +{
> + u64 ns;
> + u32 lo, hi;
> +
> + lo = ixp_read(®s->SysTimeLo);
> + hi = ixp_read(®s->SysTimeHi);
> +
> + ns = ((u64) hi) << 32;
> + ns |= lo;
> + ns <<= TICKS_NS_SHIFT;
> +
> + return ns;
> +}
> +
> +static void sys_time_write(struct ixp46x_ts_regs *regs, u64 ns)
Should use the ptp_ixp_ prefix on these functions too.
> +{
> + u32 hi, lo;
> +
> + ns >>= TICKS_NS_SHIFT;
> + hi = ns >> 32;
> + lo = ns & 0xffffffff;
> +
> + ixp_write(®s->SysTimeLo, lo);
> + ixp_write(®s->SysTimeHi, hi);
> +}
> +
> +/*
> + * PTP clock operations
> + */
> +
> +static int ptp_ixp_adjfreq(void *priv, s32 ppb)
> +{
> + u64 adj;
> + u32 diff, addend;
> + int neg_adj = 0;
> + struct ixp46x_ts_regs *regs = priv;
> +
> + if (!ppb)
> + return 0;
> +
> + if (ppb < 0) {
> + neg_adj = 1;
> + ppb = -ppb;
> + }
> + addend = DEFAULT_ADDEND;
> + adj = addend;
> + adj *= ppb;
> + diff = div_u64(adj, 1000000000ULL);
> +
> + addend = neg_adj ? addend - diff : addend + diff;
> +
> + ixp_write(®s->Addend, addend);
> +
> + return 0;
> +}
> +
> +static int ptp_ixp_adjtime(void *priv, struct timespec *ts)
> +{
> + s64 delta, now;
> + unsigned long flags;
> + struct ixp46x_ts_regs *regs = priv;
> +
> + delta = 1000000000LL * ts->tv_sec;
> + delta += ts->tv_nsec;
> +
> + spin_lock_irqsave(®ister_lock, flags);
> +
> + now = sys_time_read(regs);
> + now += delta;
> + sys_time_write(regs, now);
> +
> + spin_unlock_irqrestore(®ister_lock, flags);
> +
> + return 0;
> +}
> +
> +static int ptp_ixp_gettime(void *priv, struct timespec *ts)
> +{
> + u64 ns;
> + u32 remainder;
> + unsigned long flags;
> + struct ixp46x_ts_regs *regs = priv;
> +
> + spin_lock_irqsave(®ister_lock, flags);
> +
> + ns = sys_time_read(regs);
> +
> + spin_unlock_irqrestore(®ister_lock, flags);
> +
> + ts->tv_sec = div_u64_rem(ns, 1000000000, &remainder);
> + ts->tv_nsec = remainder;
> + return 0;
> +}
> +
> +static int ptp_ixp_settime(void *priv, struct timespec *ts)
> +{
> + u64 ns;
> + unsigned long flags;
> + struct ixp46x_ts_regs *regs = priv;
> +
> + ns = ts->tv_sec * 1000000000ULL;
> + ns += ts->tv_nsec;
> +
> + spin_lock_irqsave(®ister_lock, flags);
> +
> + sys_time_write(regs, ns);
> +
> + spin_unlock_irqrestore(®ister_lock, flags);
> +
> + return 0;
> +}
> +
> +static int ptp_ixp_gettimer(void *priv, int index, struct itimerspec *ts)
> +{
> + /* We do not offer any ancillary features at all. */
> + return -EOPNOTSUPP;
> +}
> +
> +static int ptp_ixp_settimer(void *p, int i, int abs, struct itimerspec *ts)
> +{
> + /* We do not offer any ancillary features at all. */
> + return -EOPNOTSUPP;
> +}
> +
> +static int ptp_ixp_enable(void *priv, struct ptp_clock_request *rq, int on)
> +{
> + /* We do not offer any ancillary features at all. */
> + return -EOPNOTSUPP;
> +}
> +
> +static struct ptp_clock_info ptp_ixp_caps = {
> + .owner = THIS_MODULE,
> + .name = "IXP46X timer",
> + .max_adj = 512000,
> + .n_alarm = 0,
> + .n_ext_ts = 0,
> + .n_per_out = 0,
> + .pps = 0,
> + .priv = NULL,
If the value is '0' or NULL, just leave them out of the structure initializer.
> + .adjfreq = ptp_ixp_adjfreq,
> + .adjtime = ptp_ixp_adjtime,
> + .gettime = ptp_ixp_gettime,
> + .settime = ptp_ixp_settime,
> + .gettimer = ptp_ixp_gettimer,
> + .settimer = ptp_ixp_settimer,
> + .enable = ptp_ixp_enable,
> +};
> +
> +/* module operations */
> +
> +static struct {
> + struct ixp46x_ts_regs *regs;
> + struct ptp_clock *ptp_clock;
> +} ixp_clock;
> +
> +static void __exit ptp_ixp_exit(void)
> +{
> + ptp_clock_unregister(ixp_clock.ptp_clock);
> +}
> +
> +static int __init ptp_ixp_init(void)
> +{
> + ixp_clock.regs =
> + (struct ixp46x_ts_regs __iomem *)IXP4XX_TIMESYNC_BASE_VIRT;
> +
> + ptp_ixp_caps.priv = ixp_clock.regs;
> +
> + ixp_clock.ptp_clock = ptp_clock_register(&ptp_ixp_caps);
> +
> + if (IS_ERR(ixp_clock.ptp_clock))
> + return PTR_ERR(ixp_clock.ptp_clock);
> +
> + ixp_write(&ixp_clock.regs->Addend, DEFAULT_ADDEND);
> +
> + return 0;
> +}
> +
> +module_init(ptp_ixp_init);
> +module_exit(ptp_ixp_exit);
Keep module_init and module_exit with their respective function declarations.
g.
^ permalink raw reply
* Re: [0/8] netpoll/bridge fixes
From: David Miller @ 2010-06-15 18:39 UTC (permalink / raw)
To: herbert; +Cc: shemminger, mst, frzhang, netdev, amwang, mpm
In-Reply-To: <20100611021142.GA24490@gondor.apana.org.au>
From: Herbert Xu <herbert@gondor.apana.org.au>
Date: Fri, 11 Jun 2010 12:11:42 +1000
> On Fri, Jun 11, 2010 at 08:48:39AM +1000, Herbert Xu wrote:
>> On Thu, Jun 10, 2010 at 02:59:15PM -0700, Stephen Hemminger wrote:
>> >
>> > Okay, then add a comment where in_irq is used?
>>
>> Actually let me put it into a wrapper. I'll respin the patches.
>
> OK here is a repost. And this time it really is 8 patches :)
> I've tested it lightly.
All applied to net-next-2.6, thanks Herbert.
^ permalink raw reply
* Re: [PATCH 05/12] phylib: Allow reading and writing a mii bus from atomic context.
From: Grant Likely @ 2010-06-15 18:29 UTC (permalink / raw)
To: Richard Cochran
Cc: netdev, devicetree-discuss, linuxppc-dev, linux-arm-kernel,
Krzysztof Halasa, Thomas Gleixner
In-Reply-To: <20100615170806.GB10668@riccoc20.at.omicron.at>
On Tue, Jun 15, 2010 at 11:08 AM, Richard Cochran
<richardcochran@gmail.com> wrote:
> On Tue, Jun 15, 2010 at 10:43:08AM -0600, Grant Likely wrote:
>> On Tue, Jun 15, 2010 at 10:08 AM, Richard Cochran
>> <richardcochran@gmail.com> wrote:
>> > In order to support hardware time stamping from a PHY, it is necessary to
>> > read from the PHY while running in_interrupt(). This patch allows a mii
>> > bus to operate in an atomic context. An mii_bus driver may declare itself
>> > capable for this mode. Drivers which do not do this will remain with the
>> > default that bus operations may sleep.
>> >
>> > Signed-off-by: Richard Cochran <richard.cochran@omicron.at>
>>
>> Last I checked, the MDIO bus is very slow. Is this really a good
>> idea? How much latency does MDIO access have on the hardware you are
>> working with?
>
> Yes, MDIO access is slow, and it can vary (eg bit banging
> implementations). It clear that getting PHY timestamps is costly, but
> for applications that want PTP synchronization, one is willing to pay
> the price.
>
>> I also don't like the idea of taking a spin lock during MDIO
>> operations, and the dual locking mode in the core code.
>
> Originally, the phylib used a spinlock for this. It was replaced with
> a mutex in 35b5f6b1a82b5c586e0b24c711dc6ba944e88ef1 in order to
> accommodate mdio busses that may need to sleep. So, keeping the option
> to use a spinlock is similar to the previous implementation.
That's right, and I fully agree with that change. To me, going back
to allowing spin locks is a regression because it adds a new source of
scheduling latency. Using a mutex forces users to take into account
the slow nature of MDIO access. For existing callers, this isn't a
problem because they already are designed for this characteristic. A
new user which depends on atomic access should use a different API
which doesn't take the lock with the understanding that it is may
return a failure if it doesn't support it or if it cannot perform the
operation atomically.
That still leaves the troubling MDIO induced latency issue.
g.
--
Grant Likely, B.Sc., P.Eng.
Secret Lab Technologies Ltd.
^ permalink raw reply
* Re: [RFC patch net/next] net: Hoist assigns from if?
From: Joe Perches @ 2010-06-15 18:28 UTC (permalink / raw)
To: Eric Dumazet; +Cc: David Miller, netdev
In-Reply-To: <1276625060.2541.166.camel@edumazet-laptop>
On Tue, 2010-06-15 at 20:04 +0200, Eric Dumazet wrote:
> I am very old school, and use a text editor I co-wrote in
> 1986 ;)
I gave up writing my own text editors in the 70's,
but finger habits are hard to break.
> Hmm ?
Move up to the (late?) 80's... ;)
> Oh well...
Perhaps a new git blame based command would be useful
git blame -L <range> ---history
kind of an expanded, human friendly --incremental.
Show how the file range appeared with each previous revision.
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox