* bridge not learning from locally sent gratuitous ARP?
From: Patrick Schaaf @ 2016-04-21 6:37 UTC (permalink / raw)
To: netdev
Dear netdev,
I've got a peculiar issue, and hope for clarification / workarounds here.
Scenario:
- a bridge interface br0, over some ethernet base
- a macvlan interface br0-vrrp on top, set up by keepalived, with VRRP VMAC
- keepalived regularly sending gratuitous ARP with that VRRP VMAC
- (new) an additional tap interface in br0, for an openvpn link
In principle, everything is working fine. The base keepalived setup
has been in operation for a long time, running directly over a VLAN
interface. The conversion to a bridge interface is also working
without any issues by itself. The additional tap to openvpn, and the
VPN setup it realizes, is also working fine, in principle...
Issue:
- openvpn runs at 100% CPU ....
- because it it sent all packets destined to the VRRP VMAC
- because that VMAC is not in the br0 learned MAC address table (brctl showmacs)
- thus the (production webserver outbound...) traffic is flooded to
all br0 ports
Diagnosis I did so far:
- with tcpdump, verified that I can see the gratuitous ARPs on both the macvlan
and bridge interface.
- verified that "brctl showmacs" does not contain the VRRP VMAC
- identical setup for a different VLAN with almost no traffic to the
VMAC, has openvpn running without the huge CPU consumption
- straced the openvpn daemon with the issue, seeing the packet rate
expected as tap reads / sends to the remote site
Kernel:
3.14.48 (vanilla)
keepalived 1.2.13 (with repeated gratuitous ARP support patched in)
Can anybody shed a light on how to cope with this issue?
best regards
Patrick
^ permalink raw reply
* [PATCH v2 4/4] net: thunderx: Improvement for MBX interface debug messages
From: sunil.kovvuri @ 2016-04-21 6:57 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, linux-arm-kernel, sgoutham, robert.richter,
Radoslaw Biernacki
In-Reply-To: <1461221872-38841-1-git-send-email-sunil.kovvuri@gmail.com>
From: Radoslaw Biernacki <rad@semihalf.com>
Adding debug messages in case of NACK for a mailbox message, also
did small cleanups.
Signed-off-by: Radoslaw Biernacki <rad@semihalf.com>
Signed-off-by: Sunil Goutham <sgoutham@cavium.com>
---
drivers/net/ethernet/cavium/thunder/nic_main.c | 16 ++++++++++------
drivers/net/ethernet/cavium/thunder/nicvf_main.c | 8 ++++++--
2 files changed, 16 insertions(+), 8 deletions(-)
diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
index 02e9a75..6c99257 100644
--- a/drivers/net/ethernet/cavium/thunder/nic_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
@@ -822,7 +822,7 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
mbx_addr += sizeof(u64);
}
- dev_dbg(&nic->pdev->dev, "%s: Mailbox msg %d from VF%d\n",
+ dev_dbg(&nic->pdev->dev, "%s: Mailbox msg 0x%02x from VF%d\n",
__func__, mbx.msg.msg, vf);
switch (mbx.msg.msg) {
case NIC_MBOX_MSG_READY:
@@ -832,8 +832,7 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
nic->duplex[vf] = 0;
nic->speed[vf] = 0;
}
- ret = 1;
- break;
+ goto unlock;
case NIC_MBOX_MSG_QS_CFG:
reg_addr = NIC_PF_QSET_0_127_CFG |
(mbx.qs.num << NIC_QS_ID_SHIFT);
@@ -875,8 +874,10 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
nic_tx_channel_cfg(nic, mbx.qs.num, &mbx.sq);
break;
case NIC_MBOX_MSG_SET_MAC:
- if (vf >= nic->num_vf_en)
+ if (vf >= nic->num_vf_en) {
+ ret = -1; /* NACK */
break;
+ }
lmac = mbx.mac.vf_id;
bgx = NIC_GET_BGX_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
lmac = NIC_GET_LMAC_FROM_VF_LMAC_MAP(nic->vf_lmac_map[lmac]);
@@ -936,10 +937,13 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
break;
}
- if (!ret)
+ if (!ret) {
nic_mbx_send_ack(nic, vf);
- else if (mbx.msg.msg != NIC_MBOX_MSG_READY)
+ } else if (mbx.msg.msg != NIC_MBOX_MSG_READY) {
+ dev_err(&nic->pdev->dev, "NACK for MBOX 0x%02x from VF %d\n",
+ mbx.msg.msg, vf);
nic_mbx_send_nack(nic, vf);
+ }
unlock:
nic->mbx_lock[vf] = false;
}
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
index 87d0f56..12ea73a 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -134,15 +134,19 @@ int nicvf_send_msg_to_pf(struct nicvf *nic, union nic_mbx *mbx)
/* Wait for previous message to be acked, timeout 2sec */
while (!nic->pf_acked) {
- if (nic->pf_nacked)
+ if (nic->pf_nacked) {
+ netdev_err(nic->netdev,
+ "PF NACK to mbox msg 0x%02x from VF%d\n",
+ (mbx->msg.msg & 0xFF), nic->vf_id);
return -EINVAL;
+ }
msleep(sleep);
if (nic->pf_acked)
break;
timeout -= sleep;
if (!timeout) {
netdev_err(nic->netdev,
- "PF didn't ack to mbox msg %d from VF%d\n",
+ "PF didn't ACK to mbox msg 0x%02x from VF%d\n",
(mbx->msg.msg & 0xFF), nic->vf_id);
return -EBUSY;
}
--
1.7.1
^ permalink raw reply related
* [PATCH v2 0/4] net: thunderx: Add multiqset support for DPDK
From: sunil.kovvuri @ 2016-04-21 6:57 UTC (permalink / raw)
To: netdev; +Cc: linux-kernel, linux-arm-kernel, sgoutham, robert.richter
From: Sunil Goutham <sgoutham@cavium.com>
This patch series mainly adds support for userspace application
like DPDK with a VNIC VF attached to request additional QSets
for having morethan the default 8 queues.
Changes from v1:
Fixed compilation issue reported by kbuild test robot due to changes
in 2nd patch. Now 'nic_get_vf_pdev' fn() is under CONFIG_PCI_IOV.
Jerin Jacob (1):
net: thunderx: Introduce a mailbox message to reset VF counters
Radoslaw Biernacki (3):
net: thunderx: Add multiqset support for dataplane apps
net: thunderx: add sysfs attribute for SQS/SVF assigments
net: thunderx: Improvement for MBX interface debug messages
drivers/net/ethernet/cavium/thunder/nic.h | 32 ++-
drivers/net/ethernet/cavium/thunder/nic_main.c | 325 +++++++++++++++++++---
drivers/net/ethernet/cavium/thunder/nicvf_main.c | 10 +-
3 files changed, 328 insertions(+), 39 deletions(-)
^ permalink raw reply
* [PATCH v2 1/4] net: thunderx: Introduce a mailbox message to reset VF counters
From: sunil.kovvuri @ 2016-04-21 6:57 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, linux-arm-kernel, sgoutham, robert.richter,
Jerin Jacob
In-Reply-To: <1461221872-38841-1-git-send-email-sunil.kovvuri@gmail.com>
From: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Write access to VF statistics counter register is only allowed from PF.
Added a new mailbox message to reset VF's Rx/Tx counters, this is used
by userspace DPDK.
Signed-off-by: Jerin Jacob <jerin.jacob@caviumnetworks.com>
Signed-off-by: Sunil Goutham <sgoutham@cavium.com>
---
drivers/net/ethernet/cavium/thunder/nic.h | 27 ++++++++++++++
drivers/net/ethernet/cavium/thunder/nic_main.c | 45 ++++++++++++++++++++++++
2 files changed, 72 insertions(+), 0 deletions(-)
diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h
index 83025bb..e2ac9bd 100644
--- a/drivers/net/ethernet/cavium/thunder/nic.h
+++ b/drivers/net/ethernet/cavium/thunder/nic.h
@@ -368,6 +368,7 @@ struct nicvf {
#define NIC_MBOX_MSG_PNICVF_PTR 0x14 /* Get primary qset nicvf ptr */
#define NIC_MBOX_MSG_SNICVF_PTR 0x15 /* Send sqet nicvf ptr to PVF */
#define NIC_MBOX_MSG_LOOPBACK 0x16 /* Set interface in loopback */
+#define NIC_MBOX_MSG_RESET_STAT_COUNTER 0x17 /* Reset statistics counters */
#define NIC_MBOX_MSG_CFG_DONE 0xF0 /* VF configuration done */
#define NIC_MBOX_MSG_SHUTDOWN 0xF1 /* VF is being shutdown */
@@ -484,6 +485,31 @@ struct set_loopback {
bool enable;
};
+/* Reset statistics counters */
+struct reset_stat_cfg {
+ u8 msg;
+ /* Bitmap to select NIC_PF_VNIC(vf_id)_RX_STAT(0..13) */
+ u16 rx_stat_mask;
+ /* Bitmap to select NIC_PF_VNIC(vf_id)_TX_STAT(0..4) */
+ u8 tx_stat_mask;
+ /* Bitmap to select NIC_PF_QS(0..127)_RQ(0..7)_STAT(0..1)
+ * bit14, bit15 NIC_PF_QS(vf_id)_RQ7_STAT(0..1)
+ * bit12, bit13 NIC_PF_QS(vf_id)_RQ6_STAT(0..1)
+ * ..
+ * bit2, bit3 NIC_PF_QS(vf_id)_RQ1_STAT(0..1)
+ * bit0, bit1 NIC_PF_QS(vf_id)_RQ0_STAT(0..1)
+ */
+ u16 rq_stat_mask;
+ /* Bitmap to select NIC_PF_QS(0..127)_SQ(0..7)_STAT(0..1)
+ * bit14, bit15 NIC_PF_QS(vf_id)_SQ7_STAT(0..1)
+ * bit12, bit13 NIC_PF_QS(vf_id)_SQ6_STAT(0..1)
+ * ..
+ * bit2, bit3 NIC_PF_QS(vf_id)_SQ1_STAT(0..1)
+ * bit0, bit1 NIC_PF_QS(vf_id)_SQ0_STAT(0..1)
+ */
+ u16 sq_stat_mask;
+};
+
/* 128 bit shared memory between PF and each VF */
union nic_mbx {
struct { u8 msg; } msg;
@@ -501,6 +527,7 @@ union nic_mbx {
struct sqs_alloc sqs_alloc;
struct nicvf_ptr nicvf;
struct set_loopback lbk;
+ struct reset_stat_cfg reset_stat;
};
#define NIC_NODE_ID_MASK 0x03
diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
index 95f17f8..77ee260 100644
--- a/drivers/net/ethernet/cavium/thunder/nic_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
@@ -616,6 +616,48 @@ static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
return 0;
}
+/* Reset statistics counters */
+static int nic_reset_stat_counters(struct nicpf *nic,
+ int vf, struct reset_stat_cfg *cfg)
+{
+ int i, stat, qnum;
+ u64 reg_addr;
+
+ for (i = 0; i < RX_STATS_ENUM_LAST; i++) {
+ if (cfg->rx_stat_mask & BIT(i)) {
+ reg_addr = NIC_PF_VNIC_0_127_RX_STAT_0_13 |
+ (vf << NIC_QS_ID_SHIFT) |
+ (i << 3);
+ nic_reg_write(nic, reg_addr, 0);
+ }
+ }
+
+ for (i = 0; i < TX_STATS_ENUM_LAST; i++) {
+ if (cfg->tx_stat_mask & BIT(i)) {
+ reg_addr = NIC_PF_VNIC_0_127_TX_STAT_0_4 |
+ (vf << NIC_QS_ID_SHIFT) |
+ (i << 3);
+ nic_reg_write(nic, reg_addr, 0);
+ }
+ }
+
+ for (i = 0; i <= 15; i++) {
+ qnum = i >> 1;
+ stat = i & 1 ? 1 : 0;
+ reg_addr = (vf << NIC_QS_ID_SHIFT) |
+ (qnum << NIC_Q_NUM_SHIFT) | (stat << 3);
+ if (cfg->rq_stat_mask & BIT(i)) {
+ reg_addr |= NIC_PF_QSET_0_127_RQ_0_7_STAT_0_1;
+ nic_reg_write(nic, reg_addr, 0);
+ }
+ if (cfg->sq_stat_mask & BIT(i)) {
+ reg_addr |= NIC_PF_QSET_0_127_SQ_0_7_STAT_0_1;
+ nic_reg_write(nic, reg_addr, 0);
+ }
+ }
+ return 0;
+}
+
static void nic_enable_vf(struct nicpf *nic, int vf, bool enable)
{
int bgx, lmac;
@@ -757,6 +799,9 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
case NIC_MBOX_MSG_LOOPBACK:
ret = nic_config_loopback(nic, &mbx.lbk);
break;
+ case NIC_MBOX_MSG_RESET_STAT_COUNTER:
+ ret = nic_reset_stat_counters(nic, vf, &mbx.reset_stat);
+ break;
default:
dev_err(&nic->pdev->dev,
"Invalid msg from VF%d, msg 0x%x\n", vf, mbx.msg.msg);
--
1.7.1
^ permalink raw reply related
* [PATCH v2 2/4] net: thunderx: Add multiqset support for dataplane apps
From: sunil.kovvuri @ 2016-04-21 6:57 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, linux-arm-kernel, sgoutham, robert.richter,
Radoslaw Biernacki
In-Reply-To: <1461221872-38841-1-git-send-email-sunil.kovvuri@gmail.com>
From: Radoslaw Biernacki <rad@semihalf.com>
This patch adds support to PF for allocating additional Qsets to
dataplane apps such as DPDK. Till now PF, upon host bound interface's
request it used to allocate Qsets from the free ones, but for dataplane
apps support has been added for it to request specific Qsets instead of
just PF's choice.
And also adds validation checks at different places, these are needed to
have proper secondary Qset allocation when interfaces in different domain
i.e Host, VFIO, DPDK e.t.c exist at the same time.
Some of the checks are
- Check if RSS indirection table has valid entries.
- When host bound interface requests additional Qsets, PF should
assign only those which in host domain i.e both primary VF and
secondary VFs should be using same driver. Hence added PCI driver
checks.
- If dataplane app terminates without proper shutdown then when
restarted it will request the same or different SQsets as were
assigned before. This is taken care of otherwise application
won't recover.
Removed 'sqs_used' which became redundant due to new SQset allocation scheme.
Signed-off-by: Radoslaw Biernacki <rad@semihalf.com>
Signed-off-by: Sunil Goutham <sgoutham@cavium.com>
---
drivers/net/ethernet/cavium/thunder/nic.h | 5 +-
drivers/net/ethernet/cavium/thunder/nic_main.c | 197 +++++++++++++++++++---
drivers/net/ethernet/cavium/thunder/nicvf_main.c | 2 +-
3 files changed, 174 insertions(+), 30 deletions(-)
diff --git a/drivers/net/ethernet/cavium/thunder/nic.h b/drivers/net/ethernet/cavium/thunder/nic.h
index e2ac9bd..b63278a 100644
--- a/drivers/net/ethernet/cavium/thunder/nic.h
+++ b/drivers/net/ethernet/cavium/thunder/nic.h
@@ -463,11 +463,12 @@ struct bgx_link_status {
u32 speed;
};
-/* Get Extra Qset IDs */
+/* Allocate additional SQS to VF */
struct sqs_alloc {
u8 msg;
- u8 vf_id;
+ u8 spec; /* 1 - For specific SQS allocation, 0 - For PF's choice */
u8 qs_count;
+ u8 svf[MAX_SQS_PER_VF]; /* SQS VF ids for specific allocation */
};
struct nicvf_ptr {
diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
index 77ee260..cd5e7a4 100644
--- a/drivers/net/ethernet/cavium/thunder/nic_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
@@ -29,9 +29,9 @@ struct nicpf {
void __iomem *reg_base; /* Register start address */
u8 num_sqs_en; /* Secondary qsets enabled */
u64 nicvf[MAX_NUM_VFS_SUPPORTED];
+#define NIC_VF_UNASSIGNED ((u8)0xFF)
u8 vf_sqs[MAX_NUM_VFS_SUPPORTED][MAX_SQS_PER_VF];
u8 pqs_vf[MAX_NUM_VFS_SUPPORTED];
- bool sqs_used[MAX_NUM_VFS_SUPPORTED];
struct pkind_cfg pkind;
#define NIC_SET_VF_LMAC_MAP(bgx, lmac) (((bgx & 0xF) << 4) | (lmac & 0xF))
#define NIC_GET_BGX_FROM_VF_LMAC_MAP(map) ((map >> 4) & 0xF)
@@ -46,6 +46,7 @@ struct nicpf {
u16 rssi_base[MAX_NUM_VFS_SUPPORTED];
u16 rss_ind_tbl_size;
bool mbx_lock[MAX_NUM_VFS_SUPPORTED];
+ struct pci_dev *vf_pdev[MAX_NUM_VFS_SUPPORTED];
/* MSI-X */
bool msix_enabled;
@@ -458,10 +459,18 @@ static void nic_config_rss(struct nicpf *nic, struct rss_cfg_msg *cfg)
for (; rssi < (rssi_base + cfg->tbl_len); rssi++) {
u8 svf = cfg->ind_tbl[idx] >> 3;
- if (svf)
+ if (svf && (svf <= MAX_SQS_PER_VF)) {
qset = nic->vf_sqs[cfg->vf_id][svf - 1];
- else
+ if ((qset >= MAX_NUM_VFS_SUPPORTED) ||
+ (nic->pqs_vf[qset] != cfg->vf_id)) {
+ dev_err(&nic->pdev->dev,
+ "Invalid rss table entry %d from VF %d\n",
+ cfg->ind_tbl[idx], cfg->vf_id);
+ qset = cfg->vf_id;
+ }
+ } else {
qset = cfg->vf_id;
+ }
nic_reg_write(nic, NIC_PF_RSSI_0_4097_RQ | (rssi << 3),
(qset << 3) | (cfg->ind_tbl[idx] & 0x7));
idx++;
@@ -550,7 +559,19 @@ static void nic_send_pnicvf(struct nicpf *nic, int sqs)
static void nic_send_snicvf(struct nicpf *nic, struct nicvf_ptr *nicvf)
{
union nic_mbx mbx = {};
- int sqs_id = nic->vf_sqs[nicvf->vf_id][nicvf->sqs_id];
+ int sqs_id;
+
+ if (nicvf->sqs_id >= MAX_SQS_PER_VF) {
+ nic_mbx_send_nack(nic, nicvf->vf_id);
+ return;
+ }
+
+ sqs_id = nic->vf_sqs[nicvf->vf_id][nicvf->sqs_id];
+ if ((sqs_id < nic->num_vf_en) ||
+ (nic->pqs_vf[sqs_id] != nicvf->vf_id)) {
+ nic_mbx_send_nack(nic, nicvf->vf_id);
+ return;
+ }
mbx.nicvf.msg = NIC_MBOX_MSG_SNICVF_PTR;
mbx.nicvf.sqs_id = nicvf->sqs_id;
@@ -558,47 +579,152 @@ static void nic_send_snicvf(struct nicpf *nic, struct nicvf_ptr *nicvf)
nic_send_msg_to_vf(nic, nicvf->vf_id, &mbx);
}
+#ifdef CONFIG_PCI_IOV
+/* Find and take reference to all vf devices */
+static void nic_get_vf_pdev(struct nicpf *nic, int vf_en)
+{
+ struct pci_dev *pdev = nic->pdev;
+ struct pci_dev *vfdev;
+ u16 vid = pdev->vendor;
+ u16 devid;
+ int vf = 0, pos;
+
+ pos = pci_find_ext_capability(pdev, PCI_EXT_CAP_ID_SRIOV);
+ if (!pos)
+ return;
+ pci_read_config_word(pdev, pos + PCI_SRIOV_VF_DID, &devid);
+
+ vfdev = pci_get_device(vid, devid, NULL);
+ for (; vfdev; vfdev = pci_get_device(vid, devid, vfdev)) {
+ if (!vfdev->is_virtfn)
+ continue;
+ if (vfdev->physfn != pdev)
+ continue;
+ if (vf >= vf_en)
+ continue;
+ nic->vf_pdev[vf] = vfdev;
+ pci_dev_get(vfdev);
+ ++vf;
+ }
+}
+#endif
+
+/* Release references to all vf devices */
+static void nic_put_vf_pdev(struct nicpf *nic)
+{
+ int vf;
+
+ for (vf = 0; vf < MAX_NUM_VFS_SUPPORTED; vf++) {
+ struct pci_dev *vfdev = nic->vf_pdev[vf];
+
+ nic->vf_pdev[vf] = NULL;
+ if (vfdev)
+ pci_dev_put(vfdev);
+ }
+}
+
+/* Check if pri.VF and sec.VF are in same domain i.e bound to same driver */
+static bool nic_check_svf_drv(struct nicpf *nic, u8 pvf, u8 svf)
+{
+ return pci_dev_driver(nic->vf_pdev[pvf]) ==
+ pci_dev_driver(nic->vf_pdev[svf]);
+}
+
/* Find next available Qset that can be assigned as a
* secondary Qset to a VF.
*/
-static int nic_nxt_avail_sqs(struct nicpf *nic)
+static int nic_nxt_avail_sqs(struct nicpf *nic, u8 pvf)
{
int sqs;
- for (sqs = 0; sqs < nic->num_sqs_en; sqs++) {
- if (!nic->sqs_used[sqs])
- nic->sqs_used[sqs] = true;
+ for (sqs = nic->num_vf_en;
+ sqs < (nic->num_vf_en + nic->num_sqs_en); sqs++) {
+ if ((nic->pqs_vf[sqs] == NIC_VF_UNASSIGNED) &&
+ nic_check_svf_drv(nic, pvf, sqs))
+ nic->pqs_vf[sqs] = pvf;
else
continue;
- return sqs + nic->num_vf_en;
+ return sqs;
}
return -1;
}
/* Allocate additional Qsets for requested VF */
-static void nic_alloc_sqs(struct nicpf *nic, struct sqs_alloc *sqs)
+static void nic_alloc_sqs(struct nicpf *nic, u8 pvf, struct sqs_alloc *sqs)
{
union nic_mbx mbx = {};
int idx, alloc_qs = 0;
int sqs_id;
- if (!nic->num_sqs_en)
+ if (!nic->num_sqs_en || (sqs->qs_count > MAX_SQS_PER_VF))
goto send_mbox;
- for (idx = 0; idx < sqs->qs_count; idx++) {
- sqs_id = nic_nxt_avail_sqs(nic);
- if (sqs_id < 0)
- break;
- nic->vf_sqs[sqs->vf_id][idx] = sqs_id;
- nic->pqs_vf[sqs_id] = sqs->vf_id;
- alloc_qs++;
+ if (sqs->spec) {
+ for (idx = 0; idx < sqs->qs_count; idx++) {
+ sqs_id = sqs->svf[idx];
+
+ /* Check if desired SQS is within the allowed range */
+ if (!((sqs_id >= nic->num_vf_en) &&
+ (sqs_id < (nic->num_vf_en + nic->num_sqs_en)))) {
+ dev_err(&nic->pdev->dev,
+ "Req SQS is invalid sqs->svf[%d]=%u",
+ idx, sqs_id);
+ break;
+ }
+
+ /* Check if desired SQS is free or assigned to a PVF */
+ if ((nic->pqs_vf[sqs_id] != NIC_VF_UNASSIGNED) &&
+ (nic->pqs_vf[sqs_id] != pvf)) {
+ dev_err(&nic->pdev->dev,
+ "SQS%d is already allocated to VF%u",
+ sqs_id, nic->pqs_vf[sqs_id]);
+ break;
+ }
+
+ /* Check if SQS is bound to the same driver as PVF */
+ if (!nic_check_svf_drv(nic, pvf, sqs_id)) {
+ dev_err(&nic->pdev->dev,
+ "SQS%d use different driver", sqs_id);
+ break;
+ }
+ }
+
+ if (idx != sqs->qs_count)
+ goto send_mbox;
+
+ /* Clear any existing assignments */
+ for (idx = 0; idx < MAX_SQS_PER_VF; idx++)
+ nic->vf_sqs[pvf][idx] = NIC_VF_UNASSIGNED;
+ for (idx = nic->num_vf_en;
+ idx < (nic->num_vf_en + nic->num_sqs_en); idx++) {
+ if (nic->pqs_vf[idx] == pvf)
+ nic->pqs_vf[idx] = NIC_VF_UNASSIGNED;
+ }
+
+ /* Populate VF's SQS table */
+ for (idx = 0; idx < sqs->qs_count; idx++) {
+ sqs_id = sqs->svf[idx];
+ nic->vf_sqs[pvf][idx] = sqs_id;
+ nic->pqs_vf[sqs_id] = pvf;
+ mbx.sqs_alloc.svf[idx] = sqs_id;
+ }
+ alloc_qs = idx;
+ } else {
+ for (idx = 0; idx < sqs->qs_count; idx++) {
+ sqs_id = nic_nxt_avail_sqs(nic, pvf);
+ if (sqs_id < 0)
+ break;
+ nic->vf_sqs[pvf][idx] = sqs_id;
+ nic->pqs_vf[sqs_id] = pvf;
+ mbx.sqs_alloc.svf[idx] = sqs_id;
+ }
+ alloc_qs = idx;
}
send_mbox:
mbx.sqs_alloc.msg = NIC_MBOX_MSG_ALLOC_SQS;
- mbx.sqs_alloc.vf_id = sqs->vf_id;
mbx.sqs_alloc.qs_count = alloc_qs;
- nic_send_msg_to_vf(nic, sqs->vf_id, &mbx);
+ nic_send_msg_to_vf(nic, pvf, &mbx);
}
static int nic_config_loopback(struct nicpf *nic, struct set_loopback *lbk)
@@ -776,13 +902,15 @@ static void nic_handle_mbx_intr(struct nicpf *nic, int vf)
goto unlock;
case NIC_MBOX_MSG_SHUTDOWN:
/* First msg in VF teardown sequence */
- if (vf >= nic->num_vf_en)
- nic->sqs_used[vf - nic->num_vf_en] = false;
- nic->pqs_vf[vf] = 0;
+ if (vf < nic->num_vf_en) {
+ for (i = 0; i < MAX_SQS_PER_VF; i++)
+ nic->vf_sqs[vf][i] = NIC_VF_UNASSIGNED;
+ }
+ nic->pqs_vf[vf] = NIC_VF_UNASSIGNED;
nic_enable_vf(nic, vf, false);
break;
case NIC_MBOX_MSG_ALLOC_SQS:
- nic_alloc_sqs(nic, &mbx.sqs_alloc);
+ nic_alloc_sqs(nic, vf, &mbx.sqs_alloc);
goto unlock;
case NIC_MBOX_MSG_NICVF_PTR:
nic->nicvf[vf] = mbx.nicvf.nicvf;
@@ -979,6 +1107,10 @@ static int nic_sriov_init(struct pci_dev *pdev, struct nicpf *nic)
return err;
}
+#ifdef CONFIG_PCI_IOV
+ nic_get_vf_pdev(nic, vf_en);
+#endif
+
dev_info(&pdev->dev, "SRIOV enabled, number of VF available %d\n",
vf_en);
@@ -1035,7 +1167,7 @@ static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct device *dev = &pdev->dev;
struct nicpf *nic;
- int err;
+ int err, vf, sqs;
BUILD_BUG_ON(sizeof(union nic_mbx) > 16);
@@ -1090,6 +1222,13 @@ static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
/* Set RSS TBL size for each VF */
nic->rss_ind_tbl_size = NIC_MAX_RSS_IDR_TBL_SIZE;
+ /* Initialize all VF's primary Qset */
+ for (vf = 0; vf < MAX_NUM_VFS_SUPPORTED; vf++) {
+ nic->pqs_vf[vf] = NIC_VF_UNASSIGNED;
+ for (sqs = 0; sqs < MAX_SQS_PER_VF; sqs++)
+ nic->vf_sqs[vf][sqs] = NIC_VF_UNASSIGNED;
+ }
+
/* Register interrupts */
err = nic_register_interrupts(nic);
if (err)
@@ -1114,8 +1253,10 @@ static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
err_disable_sriov:
- if (nic->flags & NIC_SRIOV_ENABLED)
+ if (nic->flags & NIC_SRIOV_ENABLED) {
+ nic_put_vf_pdev(nic);
pci_disable_sriov(pdev);
+ }
err_unregister_interrupts:
nic_unregister_interrupts(nic);
err_release_regions:
@@ -1130,8 +1271,10 @@ static void nic_remove(struct pci_dev *pdev)
{
struct nicpf *nic = pci_get_drvdata(pdev);
- if (nic->flags & NIC_SRIOV_ENABLED)
+ if (nic->flags & NIC_SRIOV_ENABLED) {
+ nic_put_vf_pdev(nic);
pci_disable_sriov(pdev);
+ }
if (nic->check_link) {
/* Destroy work Queue */
diff --git a/drivers/net/ethernet/cavium/thunder/nicvf_main.c b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
index bfee298..87d0f56 100644
--- a/drivers/net/ethernet/cavium/thunder/nicvf_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nicvf_main.c
@@ -386,7 +386,7 @@ static void nicvf_request_sqs(struct nicvf *nic)
return;
mbx.sqs_alloc.msg = NIC_MBOX_MSG_ALLOC_SQS;
- mbx.sqs_alloc.vf_id = nic->vf_id;
+ mbx.sqs_alloc.spec = 0; /* Let PF choose which SQS to alloc */
mbx.sqs_alloc.qs_count = nic->sqs_count;
if (nicvf_send_msg_to_pf(nic, &mbx)) {
/* No response from PF */
--
1.7.1
^ permalink raw reply related
* [PATCH v2 3/4] net: thunderx: add sysfs attribute for SQS/SVF assigments
From: sunil.kovvuri @ 2016-04-21 6:57 UTC (permalink / raw)
To: netdev
Cc: linux-kernel, linux-arm-kernel, sgoutham, robert.richter,
Radoslaw Biernacki
In-Reply-To: <1461221872-38841-1-git-send-email-sunil.kovvuri@gmail.com>
From: Radoslaw Biernacki <rad@semihalf.com>
With this sysfs attribute (sriov_sqs_assignment) administrator will be
able to read the current assigment of SQS/SVF for a given VF. This is
useful to decide which VFs needs to be attached to UIO for a successful
allocation of secondary Qsets
Signed-off-by: Radoslaw Biernacki <rad@semihalf.com>
Signed-off-by: Sunil Goutham <sgoutham@cavium.com>
---
drivers/net/ethernet/cavium/thunder/nic_main.c | 67 +++++++++++++++++++++++-
1 files changed, 66 insertions(+), 1 deletions(-)
diff --git a/drivers/net/ethernet/cavium/thunder/nic_main.c b/drivers/net/ethernet/cavium/thunder/nic_main.c
index cd5e7a4..02e9a75 100644
--- a/drivers/net/ethernet/cavium/thunder/nic_main.c
+++ b/drivers/net/ethernet/cavium/thunder/nic_main.c
@@ -1163,6 +1163,60 @@ static void nic_poll_for_link(struct work_struct *work)
queue_delayed_work(nic->check_link, &nic->dwork, HZ * 2);
}
+ssize_t sriov_sqs_assignment_show(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct pci_dev *pdev = container_of(dev, struct pci_dev, dev);
+ struct pci_dev *vf_dev;
+ struct pci_driver *vf_drv;
+ struct nicpf *nic = pci_get_drvdata(pdev);
+ size_t vf, off, svf_idx;
+
+ off = scnprintf(buf, PAGE_SIZE, "%u\n", nic->num_vf_en);
+
+ for (vf = 0; vf < nic->num_vf_en; vf++) {
+ vf_dev = nic->vf_pdev[vf];
+ vf_drv = vf_dev ? pci_dev_driver(vf_dev) : NULL;
+ if (off >= PAGE_SIZE)
+ break;
+ off += scnprintf(&buf[off], PAGE_SIZE - off,
+ "%zu %04x:%02x:%02x.%d %s %c:",
+ vf, pci_domain_nr(vf_dev->bus),
+ vf_dev->bus->number, PCI_SLOT(vf_dev->devfn),
+ PCI_FUNC(vf_dev->devfn),
+ vf_drv ? vf_drv->name : "no-driver",
+ nic->vf_enabled[vf] ? '+' : '-');
+ for (svf_idx = 0; svf_idx < MAX_SQS_PER_VF; svf_idx++) {
+ if (off >= PAGE_SIZE)
+ break;
+ if (nic->vf_sqs[vf][svf_idx] == NIC_VF_UNASSIGNED)
+ break;
+ off += scnprintf(&buf[off], PAGE_SIZE - off, " %d",
+ nic->vf_sqs[vf][svf_idx]);
+ }
+ if (off >= PAGE_SIZE)
+ break;
+ off += scnprintf(&buf[off], PAGE_SIZE - off, "\n");
+ }
+
+ for (vf = nic->num_vf_en; vf < nic->num_vf_en + nic->num_sqs_en; vf++) {
+ vf_dev = nic->vf_pdev[vf];
+ vf_drv = vf_dev ? pci_dev_driver(vf_dev) : NULL;
+ if (off >= PAGE_SIZE)
+ break;
+ off += scnprintf(&buf[off], PAGE_SIZE - off,
+ "%zu %04x:%02x:%02x.%d %s: %u\n",
+ vf, pci_domain_nr(vf_dev->bus),
+ vf_dev->bus->number, PCI_SLOT(vf_dev->devfn),
+ PCI_FUNC(vf_dev->devfn),
+ vf_drv ? vf_drv->name : "no-driver",
+ nic->pqs_vf[vf]);
+ }
+
+ return off;
+}
+DEVICE_ATTR_RO(sriov_sqs_assignment);
+
static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
{
struct device *dev = &pdev->dev;
@@ -1239,12 +1293,18 @@ static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
if (err)
goto err_unregister_interrupts;
+ err = device_create_file(dev, &dev_attr_sriov_sqs_assignment);
+ if (err) {
+ err = -ENOMEM;
+ goto err_disable_sriov;
+ }
+
/* Register a physical link status poll fn() */
nic->check_link = alloc_workqueue("check_link_status",
WQ_UNBOUND | WQ_MEM_RECLAIM, 1);
if (!nic->check_link) {
err = -ENOMEM;
- goto err_disable_sriov;
+ goto err_remove_sysfs_attr;
}
INIT_DELAYED_WORK(&nic->dwork, nic_poll_for_link);
@@ -1252,6 +1312,8 @@ static int nic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
return 0;
+err_remove_sysfs_attr:
+ device_remove_file(dev, &dev_attr_sriov_sqs_assignment);
err_disable_sriov:
if (nic->flags & NIC_SRIOV_ENABLED) {
nic_put_vf_pdev(nic);
@@ -1270,6 +1332,9 @@ err_disable_device:
static void nic_remove(struct pci_dev *pdev)
{
struct nicpf *nic = pci_get_drvdata(pdev);
+ struct device *dev = &pdev->dev;
+
+ device_remove_file(dev, &dev_attr_sriov_sqs_assignment);
if (nic->flags & NIC_SRIOV_ENABLED) {
nic_put_vf_pdev(nic);
--
1.7.1
^ permalink raw reply related
* Re: [PATCH 4/4] drm/i915: Move ioremap_wc tracking onto VMA
From: Daniel Vetter @ 2016-04-21 7:27 UTC (permalink / raw)
To: Luis R. Rodriguez
Cc: David Hildenbrand, David Airlie, netdev, intel-gfx, linux-kernel,
dri-devel, Peter Zijlstra (Intel), Daniel Vetter, Dan Williams,
Yishai Hadas, Ingo Molnar, linux-rdma
In-Reply-To: <20160420212727.GS1990@wotan.suse.de>
On Wed, Apr 20, 2016 at 11:27:27PM +0200, Luis R. Rodriguez wrote:
> On Wed, Apr 20, 2016 at 01:17:30PM +0200, Daniel Vetter wrote:
> > On Wed, Apr 20, 2016 at 11:10:54AM +0200, Luis R. Rodriguez wrote:
> > > Reason I ask is since I noticed a while ago a lot of drivers
> > > were using info->fix.smem_start and info->fix.smem_len consistently
> > > for their ioremap'd areas it might make sense instead to let the
> > > internal framebuffer (register_framebuffer()) optionally manage the
> > > ioremap_wc() for drivers, given that this is pretty generic stuff.
> >
> > All that legacy fbdev stuff is just for legacy support, and I prefer to
> > have that as dumb as possible. There's been some discussion even around
> > lifting the "kick out firmware fb driver" out of fbdev, since we'd need it
> > to have a simple drm driver for e.g. uefi.
> >
> > But I definitely don't want a legacy horror show like fbdev to
> > automagically take care of device mappings for drivers.
>
> Makes sense, it also still begs the question if more modern APIs
> could manage the ioremap for you. Evidence shows people get
> sloppy and if things were done internally with helpers it may
> be easier to later make adjustments.
Real gpus generally have so much mmio space that you want to ioremap them
on demand. At least if you still care about 32bit support. And on-die gpus
on socs or similar tend to not have an mmio range to access the gfx
remapping range at all, but instead expect that to be done with gpu
pagetables.
So at least with gpus I don't see a real demand for this, and the existing
users are mostly old fbdev drivers that really no one should be touching
;-)
Cheers, Daniel
--
Daniel Vetter
Software Engineer, Intel Corporation
http://blog.ffwll.ch
_______________________________________________
Intel-gfx mailing list
Intel-gfx@lists.freedesktop.org
https://lists.freedesktop.org/mailman/listinfo/intel-gfx
^ permalink raw reply
* [RFC PATCH] gro: Partly revert "net: gro: allow to build full sized skb"
From: Steffen Klassert @ 2016-04-21 7:40 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Sowmini Varadhan, netdev
This partly reverts the below mentioned patch because on
forwarding, such skbs can't be offloaded to a NIC.
We need this to get IPsec GRO for forwarding to work properly,
otherwise the GRO aggregated packets get segmented again by
the GSO layer. Although discovered when implementing IPsec GRO,
this is a general problem in the forwarding path.
-------------------------------------------------------------------------
commit 8a29111c7ca68d928dfab58636f3f6acf0ac04f7
Author: Eric Dumazet <edumazet@google.com>
Date: Tue Oct 8 09:02:23 2013 -0700
net: gro: allow to build full sized skb
skb_gro_receive() is currently limited to 16 or 17 MSS per GRO skb,
typically 24616 bytes, because it fills up to MAX_SKB_FRAGS frags.
It's relatively easy to extend the skb using frag_list to allow
more frags to be appended into the last sk_buff.
This still builds very efficient skbs, and allows reaching 45 MSS per
skb.
(45 MSS GRO packet uses one skb plus a frag_list containing 2 additional
sk_buff)
High speed TCP flows benefit from this extension by lowering TCP stack
cpu usage (less packets stored in receive queue, less ACK packets
processed)
Forwarding setups could be hurt, as such skbs will need to be
linearized, although its not a new problem, as GRO could already
provide skbs with a frag_list.
We could make the 65536 bytes threshold a tunable to mitigate this.
(First time we need to linearize skb in skb_needs_linearize(), we could
lower the tunable to ~16*1460 so that following skb_gro_receive() calls
build smaller skbs)
Signed-off-by: Eric Dumazet <edumazet@google.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
---------------------------------------------------------------------------
Signed-off-by: Steffen Klassert <steffen.klassert@secunet.com>
---
Hi Eric, this is a followup on our discussion at the netdev
conference. Would you still be ok with this revert, or do
you think there is a better solution in sight?
The full IPsec patchset for what I need this can be found here:
https://git.kernel.org/cgit/linux/kernel/git/klassert/linux-stk.git/log/?h=net-next-ipsec-offload-work
net/core/skbuff.c | 5 ++---
1 file changed, 2 insertions(+), 3 deletions(-)
diff --git a/net/core/skbuff.c b/net/core/skbuff.c
index 4cc594c..fb11a9b 100644
--- a/net/core/skbuff.c
+++ b/net/core/skbuff.c
@@ -3347,7 +3347,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
int nr_frags = pinfo->nr_frags + i;
if (nr_frags > MAX_SKB_FRAGS)
- goto merge;
+ return -E2BIG;
offset -= headlen;
pinfo->nr_frags = nr_frags;
@@ -3380,7 +3380,7 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
unsigned int first_offset;
if (nr_frags + 1 + skbinfo->nr_frags > MAX_SKB_FRAGS)
- goto merge;
+ return -E2BIG;
first_offset = skb->data -
(unsigned char *)page_address(page) +
@@ -3400,7 +3400,6 @@ int skb_gro_receive(struct sk_buff **head, struct sk_buff *skb)
goto done;
}
-merge:
delta_truesize = skb->truesize;
if (offset > headlen) {
unsigned int eat = offset - headlen;
--
1.9.1
^ permalink raw reply related
* Re: linux-next: zillions of lockdep whinges in include/net/sock.h:1408
From: Hannes Frederic Sowa @ 2016-04-21 7:42 UTC (permalink / raw)
To: Valdis Kletnieks, David S. Miller; +Cc: netdev, linux-kernel
In-Reply-To: <66816.1461198639@turing-police.cc.vt.edu>
Hi,
On Thu, Apr 21, 2016, at 02:30, Valdis Kletnieks wrote:
> linux-next 20160420 is whining at an incredible rate - in 20 minutes of
> uptime, I piled up some 41,000 hits from all over the place (cleaned up
> to skip the CPU and PID so the list isn't quite so long):
Thanks for the report. Can you give me some more details:
Is this an nfs socket? Do you by accident know if this socket went
through xs_reclassify_socket at any point? We do hold the appropriate
locks at that point but I fear that the lockdep reinitialization
confused lockdep.
Thanks,
Hannes
^ permalink raw reply
* Re: [PATCH net-next 0/7] net: network drivers should not depend on geneve/vxlan
From: Hannes Frederic Sowa @ 2016-04-21 7:43 UTC (permalink / raw)
To: David Miller; +Cc: netdev, jesse
In-Reply-To: <20160419.211134.2163748309501010595.davem@davemloft.net>
Hi David,
On Wed, Apr 20, 2016, at 03:11, David Miller wrote:
> From: Hannes Frederic Sowa <hannes@stressinduktion.org>
> Date: Wed, 20 Apr 2016 03:06:13 +0200
>
> > On Wed, Apr 20, 2016, at 02:27, David Miller wrote:
> >> From: Hannes Frederic Sowa <hannes@stressinduktion.org>
> >> Date: Mon, 18 Apr 2016 21:19:41 +0200
> >>
> >> > This patchset removes the dependency of network drivers on vxlan or
> >> > geneve, so those don't get autoloaded when the nic driver is loaded.
> >> >
> >> > Also audited the code such that vxlan_get_rx_port and geneve_get_rx_port
> >> > are not called without rtnl lock.
> >>
> >> In net-next, the 'qed' driver has tunneling offload support too.
> >> Don't you need to update this series to handle that driver as
> >> well?
> >
> > I audited qede as well:
> >
> > qede calls {vxlan,geneve}_get_rx_port only from ndo_open which isn't
> > reused anywhere else in the driver, only from ndo_open, which holds
> > rtnl_lock also. Thus the driver is safe and doesn't need a change.
>
> I'm talking about your final patches which elide the dependencies.
could you look at this again? If you have further feedback I am happy to
incooperate those.
Thank you,
Hannes
^ permalink raw reply
* Re: IPv6 patch mysteriously breaks IPv4 VPN
From: Bjørn Mork @ 2016-04-21 8:04 UTC (permalink / raw)
To: Valdis Kletnieks; +Cc: David S. Miller, netdev, linux-kernel
In-Reply-To: <15023.1461205453@turing-police.cc.vt.edu>
Valdis Kletnieks <Valdis.Kletnieks@vt.edu> writes:
> I'll say up front - no, I do *not* have a clue why this commit causes this
> problem - it makes exactly zero fsking sense.
>
> Scenario: $WORK is blessed with a Juniper VPN system. I've been
> seeing for a while now (since Dec-ish) an issue where at startup,
> the tun0 device will get wedged. ifconfig reports this:
>
> tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1400
> inet 172.27.1.165 netmask 255.255.255.255 destination 172.27.1.165
> inet6 fe80::6802:d95c:f3f4:2a6f prefixlen 64 scopeid 0x20<link>
> unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC)
> RX packets 0 bytes 0 (0.0 B)
> RX errors 0 dropped 0 overruns 0 frame 0
> TX packets 1 bytes 48 (48.0 B)
> TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
>
> and no more packets cross - not even a ping.
>
> Yes, the tunnel is ipv4 only, and only ipv4 routes get set by the VPN software.
>
> bisect results confirmed - linux-next 20160327 is bad, but 20160420 with this
> one conmmit reverted works.
>
> % git bisect bad
> cc9da6cc4f56e05cc9e591459fe0192727ff58b3 is the first bad commit
> commit cc9da6cc4f56e05cc9e591459fe0192727ff58b3
> Author: Bjørn Mork <bjorn@mork.no>
> Date: Wed Dec 16 16:44:38 2015 +0100
>
> ipv6: addrconf: use stable address generator for ARPHRD_NONE
This is The Twilight Zone ;)
So, unless there is a bug I don't see here, the effect of that patch on
a tun interface is one thing only: a link local address is allocated by
default. Which again will enable IPv6 autoconf on the interface,
causing us to send one or more router solicitations.
The only problem I can think of is if the userspace application stops
reading from the fd when it sees that RS. Your counters shows one 48
bytes TX packet, which matches the expected size of the RS (no options
since there is no link layer address).
If this is correct, then I don't think reverting that patch will solve
the problem, only hide it. The application will still fail if the
system is configured for stable privacy addresses, or set up in some
other way to configure a link local address. I believe the stable
privacy use case must be considered, since it is a netns wide setting
and there isn't really any way to deconfigure it once configured. Any
system using stable privacy addressing will see this bug, with or
without that patch.
Lots of assumptions... Let's try to verify some of them first.
1) revert the patch (or run an older kernel) and configure stable
privacy (feel free to use a more random secret than '::'):
echo :: >/proc/sys/net/ipv6/conf/default/stable_secret
Does that make the VPN tunnel fail too?
The remaining tests are interface specific. If you are are able to
configure settings for the tun interface then do that, otherwise you'll
have to change the defaults before letting the application create the
tun interface.
2) run a kernel with the patch, but disable IPv6 on the tun interface:
echo 1 >/proc/sys/net/ipv6/conf/tun0/disable_ipv6
Does the VPN tunnel work now?
3) run a kernel with the patch and keep IPv6 enabled, but disable
RS. E.g. by:
echo 0 >/proc/sys/net/ipv6/conf/tun0/router_solicitations
4) run a kernel with the patch, but explictly set the addrgen mode to
none to prevent generating a link local address:
ip link set tun0 addrgenmode none
If my assumptions are correct then the first test should make the VPN
software fail even without the patch, while the last 3 tests should all
make it work with the patch in place.
I still don't know how to deal with this, though. I don't object to
reverting the patch if that is necessary, even if it is just to work
around a stupid userspace bug. But I believe the stable privacy use
case is real, and if that causes the application to bug out anyway then
there isn't much point, is there?
The Linux kernel will send RS by default. Depending on that not
happening on specific interface types, because there currently isn't any
valid method to autogenerate addresses, is a little fragile. New
address generation methods for different interface types have been added
over time. And will continue to be added. There isn't really anything
special about tun interfaces in this regard.
If some application really cares, then it should explicitly disable the
RS and/or the address generation. We do provide knobs for both.
Bjørn
^ permalink raw reply
* Re: IPv6 patch mysteriously breaks IPv4 VPN
From: Hannes Frederic Sowa @ 2016-04-21 8:08 UTC (permalink / raw)
To: Valdis Kletnieks, bjorn, David S. Miller; +Cc: netdev, linux-kernel
In-Reply-To: <15023.1461205453@turing-police.cc.vt.edu>
On 21.04.2016 04:24, Valdis Kletnieks wrote:
> I'll say up front - no, I do *not* have a clue why this commit causes this
> problem - it makes exactly zero fsking sense.
>
> Scenario: $WORK is blessed with a Juniper VPN system. I've been
> seeing for a while now (since Dec-ish) an issue where at startup,
> the tun0 device will get wedged. ifconfig reports this:
>
> tun0: flags=4305<UP,POINTOPOINT,RUNNING,NOARP,MULTICAST> mtu 1400
> inet 172.27.1.165 netmask 255.255.255.255 destination 172.27.1.165
> inet6 fe80::6802:d95c:f3f4:2a6f prefixlen 64 scopeid 0x20<link>
> unspec 00-00-00-00-00-00-00-00-00-00-00-00-00-00-00-00 txqueuelen 500 (UNSPEC)
> RX packets 0 bytes 0 (0.0 B)
> RX errors 0 dropped 0 overruns 0 frame 0
> TX packets 1 bytes 48 (48.0 B)
> TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
Can you show us a ip -d l l ?
Thanks,
Hannes
^ permalink raw reply
* Re: linux-next: zillions of lockdep whinges in include/net/sock.h:1408
From: Valdis.Kletnieks @ 2016-04-21 9:05 UTC (permalink / raw)
To: Hannes Frederic Sowa; +Cc: David S. Miller, netdev, linux-kernel
In-Reply-To: <1461224532.4101068.585250481.7A43E285@webmail.messagingengine.com>
[-- Attachment #1: Type: text/plain, Size: 1009 bytes --]
On Thu, 21 Apr 2016 09:42:12 +0200, Hannes Frederic Sowa said:
> Hi,
>
> On Thu, Apr 21, 2016, at 02:30, Valdis Kletnieks wrote:
> > linux-next 20160420 is whining at an incredible rate - in 20 minutes of
> > uptime, I piled up some 41,000 hits from all over the place (cleaned up
> > to skip the CPU and PID so the list isn't quite so long):
>
> Thanks for the report. Can you give me some more details:
>
> Is this an nfs socket? Do you by accident know if this socket went
> through xs_reclassify_socket at any point? We do hold the appropriate
> locks at that point but I fear that the lockdep reinitialization
> confused lockdep.
It wasn't an NFS socket, as NFS wasn't even active at the time. I'm reasonably
sure that multiple sockets were in play, given that tcp_v6_rcv and
udpv6_queue_rcv_skb were both implicated. I strongly suspect that pretty much
any IPv6 traffic could do it - the frequency dropped off quite a bit when I
closed firefox, which is usually a heavy network hitter on my laptop.
[-- Attachment #2: Type: application/pgp-signature, Size: 848 bytes --]
^ permalink raw reply
* [PATCH 0/6] Add Shared MDIO framework for iProc based SoCs
From: Pramod Kumar @ 2016-04-21 9:18 UTC (permalink / raw)
To: Rob Herring, Catalin Marinas, Will Deacon, Masahiro Yamada,
Chen-Yu Tsai
Cc: BCM Kernel Feedback, Pawel Moll, Mark Rutland, Arnd Bergmann,
Suzuki K Poulose, Punit Agrawal,
devicetree-u79uwXL29TY76Z2rM5mHXA,
linux-arm-kernel-IAPFreCvJWM7uuMidbF8XUB+6BGkLq7r,
linux-kernel-u79uwXL29TY76Z2rM5mHXA,
netdev-u79uwXL29TY76Z2rM5mHXA, Pramod Kumar
Broadcom iProc based SoCs uses MDIO bus for programming PHYs belonging to
different I/O subsystem like USB, SATA, PCIe, ETHERNET etc. Every subsystem
is referred as "Master" When a master is selected, all PHYs belonging to
this subsystem get active on the MDIO bus and responds to MDIO transaction.
In this way one MDIO controller is shared among all masters hence named as
"Shared MDIO controller".
We have two important entities in "Shared MDIO Bus" framework:
1) shared_mdio_master and
2) shared_mdio_driver.
The shared MDIO controller driver is registered as platform driver and it
creates shared_mdio_master instances and adds them to "Shared MDIO Bus"
framework. The "Shared MDIO Bus" framework will try to match-n-probe each
shared_mdio_master instance with all available shared_mdio_driver based on
DT matching. The shared_mdio_driver will acts as phy provider for
respective PHY frameworks and it will access PHY registers only using
"Shared MDIO Bus" framework APIs. All PHY read/write from
shared_mdio_driver will eventually reach shared MDIO controller driver
(who originally created shared_mdio_master instances) and shared MDIO
controller driver will serialized these PHY read/write as required.
This patch set includes Shared MDIO Bus framework, Shared MDIO block driver
and one Shared MDIO driver, ETHERNET PHY provider driver.
shared_mdio.c: This is the bus framework where all masters are registered
via shared MDIO block driver.
iproc_shared_mdio.c: Represent the shared MDIO block driver. The driver
registers all masters to shared mdio bus framework.
mdio-bcm-iproc-shared.c: Master driver which registers ETHERNET phy to
legacy MII framework.
In future there will be more driver for SATA, USB, PCIe masters which will
register phys for their subsystem.
Patch series is developed based on Linux v4.6-rc1 and available at:
repo: https://github.com/Broadcom/arm64-linux.git
branch: shared_mdio_v0
Pramod Kumar (6):
bus: Add shared MDIO bus framework
Documentation: DT binding doc for iProc Shared MDIO Controller.
bus: Add platform driver for iProc shared MDIO Controller
dt: Add Shared MDIO Controller node for NS2
Documentation: Binding doc for ethernet master in NS2
net:phy: Add Ethernet Master for iProc Shared MDIO Controller
.../bindings/bus/brcm,iproc-shared-mdio.txt | 76 ++++++
.../bindings/net/brcm,iproc-mdio-shared.txt | 32 +++
arch/arm64/boot/dts/broadcom/ns2-svk.dts | 15 ++
arch/arm64/boot/dts/broadcom/ns2.dtsi | 8 +
drivers/bus/Kconfig | 22 ++
drivers/bus/Makefile | 2 +
drivers/bus/iproc_shared_mdio.c | 287 +++++++++++++++++++++
drivers/bus/shared_mdio.c | 179 +++++++++++++
drivers/net/phy/Kconfig | 11 +
drivers/net/phy/Makefile | 1 +
drivers/net/phy/mdio-bcm-iproc-shared.c | 116 +++++++++
include/linux/shared_mdio.h | 123 +++++++++
12 files changed, 872 insertions(+)
create mode 100644 Documentation/devicetree/bindings/bus/brcm,iproc-shared-mdio.txt
create mode 100644 Documentation/devicetree/bindings/net/brcm,iproc-mdio-shared.txt
create mode 100644 drivers/bus/iproc_shared_mdio.c
create mode 100644 drivers/bus/shared_mdio.c
create mode 100644 drivers/net/phy/mdio-bcm-iproc-shared.c
create mode 100644 include/linux/shared_mdio.h
--
1.9.1
--
To unsubscribe from this list: send the line "unsubscribe devicetree" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* [PATCH 1/6] bus: Add shared MDIO bus framework
From: Pramod Kumar @ 2016-04-21 9:18 UTC (permalink / raw)
To: Rob Herring, Catalin Marinas, Will Deacon, Masahiro Yamada,
Chen-Yu Tsai
Cc: Mark Rutland, devicetree, Pawel Moll, Arnd Bergmann,
Suzuki K Poulose, netdev, Punit Agrawal, linux-kernel,
Pramod Kumar, BCM Kernel Feedback, linux-arm-kernel, Anup Patel
In-Reply-To: <1461230323-27891-1-git-send-email-pramod.kumar@broadcom.com>
Add a common shared MDIO bus framework for sharing single (or few) MDIO
bus across IO subsystems such as SATA, PCIe, USB, and Ethernet.
The IO specific PHY drivers will register to common shared MDIO
bus as shared MDIO drivers and access the MDIO bus only using
shared MDIO APIs.
Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
Signed-off-by: Anup Patel <anup.patel@broadcom.com>
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
Reviewed-by: Vikram Prakash <vikram.prakash@broadcom.com>
---
drivers/bus/Kconfig | 11 +++
drivers/bus/Makefile | 1 +
drivers/bus/shared_mdio.c | 179 ++++++++++++++++++++++++++++++++++++++++++++
include/linux/shared_mdio.h | 123 ++++++++++++++++++++++++++++++
4 files changed, 314 insertions(+)
create mode 100644 drivers/bus/shared_mdio.c
create mode 100644 include/linux/shared_mdio.h
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index d4a3a31..1b51b1a 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -107,6 +107,17 @@ config OMAP_OCP2SCP
OCP2SCP and in OMAP5, both USB PHY and SATA PHY is connected via
OCP2SCP.
+config SHARED_MDIO
+ bool "Shared MDIO bus"
+ depends on OF
+
+ help
+ Shared MDIO bus implementation for SoCs having common MDIO bus
+ for different IO subsystems. All masters should be registered to
+ this bus via a platform driver using shared framework API.
+ Respective drivers would be called matching a compatible string
+ provided in master node.
+
config SIMPLE_PM_BUS
bool "Simple Power-Managed Bus Driver"
depends on OF && PM
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index ccff007..2b6d6e9 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -19,3 +19,4 @@ obj-$(CONFIG_SUNXI_RSB) += sunxi-rsb.o
obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
+obj-$(CONFIG_SHARED_MDIO) += shared_mdio.o
diff --git a/drivers/bus/shared_mdio.c b/drivers/bus/shared_mdio.c
new file mode 100644
index 0000000..909af73
--- /dev/null
+++ b/drivers/bus/shared_mdio.c
@@ -0,0 +1,179 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Shared MDIO Bus
+ */
+
+#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
+
+#include <linux/errno.h>
+#include <linux/idr.h>
+#include <linux/of_device.h>
+#include <linux/stddef.h>
+#include <linux/module.h>
+#include <linux/shared_mdio.h>
+#include <linux/slab.h>
+
+static DEFINE_IDA(shared_mdio_ida);
+
+static void shared_mdio_release_master(struct device *dev)
+{
+ struct shared_mdio_master *master = to_shared_mdio_master(dev);
+
+ ida_simple_remove(&shared_mdio_ida, master->dev_num);
+ kfree(master);
+}
+
+struct shared_mdio_master *shared_mdio_alloc_master(struct device *parent,
+ struct device_node *node)
+{
+ int ret = 0;
+ struct shared_mdio_master *master;
+
+ master = kzalloc(sizeof(*master), GFP_KERNEL);
+ if (!master) {
+ ret = -ENOMEM;
+ goto fail1;
+ }
+
+ master->dev.parent = parent;
+ master->dev.bus = &shared_mdio_bus;
+ master->dev.release = shared_mdio_release_master;
+
+ device_initialize(&master->dev);
+
+ ret = ida_simple_get(&shared_mdio_ida, 0, 0, GFP_KERNEL);
+ if (ret < 0)
+ goto fail2;
+ master->dev_num = ret;
+
+ dev_set_name(&master->dev, "shared-mdio-master%d", master->dev_num);
+
+ of_node_get(node);
+ master->dev.of_node = node;
+
+ return master;
+
+fail2:
+ kfree(master);
+fail1:
+ return ERR_PTR(ret);
+}
+EXPORT_SYMBOL(shared_mdio_alloc_master);
+
+int shared_mdio_add_master(struct shared_mdio_master *master)
+{
+ if (!master)
+ return -EINVAL;
+
+ return device_add(&master->dev);
+}
+EXPORT_SYMBOL(shared_mdio_add_master);
+
+static int shared_mdio_driver_probe(struct device *dev)
+{
+ int rc;
+ struct shared_mdio_master *master = to_shared_mdio_master(dev);
+ struct shared_mdio_driver *drv = to_shared_mdio_driver(dev->driver);
+
+ if (!drv->probe)
+ return -ENODEV;
+
+ rc = drv->probe(master);
+ if (rc)
+ return rc;
+
+ return 0;
+}
+
+static int shared_mdio_driver_remove(struct device *dev)
+{
+ struct shared_mdio_driver *drv = to_shared_mdio_driver(dev->driver);
+
+ if (drv->remove)
+ return drv->remove(to_shared_mdio_master(dev));
+
+ return 0;
+}
+
+static void shared_mdio_driver_shutdown(struct device *dev)
+{
+ struct shared_mdio_driver *drv = to_shared_mdio_driver(dev->driver);
+
+ if (drv->shutdown)
+ drv->shutdown(to_shared_mdio_master(dev));
+}
+
+int __shared_mdio_register_driver(struct shared_mdio_driver *drv,
+ struct module *owner)
+{
+ int rc;
+
+ drv->driver.bus = &shared_mdio_bus;
+ drv->driver.owner = owner;
+ drv->driver.probe = shared_mdio_driver_probe;
+ drv->driver.remove = shared_mdio_driver_remove;
+ drv->driver.shutdown = shared_mdio_driver_shutdown;
+
+ rc = driver_register(&drv->driver);
+ if (rc) {
+ pr_err("driver_register() failed for %s, error: %d\n",
+ drv->driver.name, rc);
+ return rc;
+ }
+
+ return 0;
+}
+EXPORT_SYMBOL(__shared_mdio_register_driver);
+
+static int shared_mdio_bus_match(struct device *dev, struct device_driver *drv)
+{
+ /* Attempt an OF style match */
+ if (of_driver_match_device(dev, drv))
+ return 1;
+
+ return 0;
+}
+
+struct bus_type shared_mdio_bus = {
+ .name = "shared_mdio",
+ .match = shared_mdio_bus_match,
+};
+EXPORT_SYMBOL(shared_mdio_bus);
+
+static int __init shared_mdio_init(void)
+{
+ int rc;
+
+ rc = bus_register(&shared_mdio_bus);
+ if (rc) {
+ pr_err("Failed to register shared_mdio bus, error: %d\n", rc);
+ return rc;
+ }
+
+ return 0;
+}
+
+static void __exit shared_mdio_exit(void)
+{
+ bus_unregister(&shared_mdio_bus);
+
+ ida_destroy(&shared_mdio_ida);
+}
+
+subsys_initcall(shared_mdio_init);
+module_exit(shared_mdio_exit);
+
+MODULE_DESCRIPTION("Shared MDIO Bus");
+MODULE_AUTHOR("Anup Patel <anup.patel@broadcom.com>");
+MODULE_AUTHOR("Pramod Kumar <pramod.kumar@broadcom.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/shared_mdio.h b/include/linux/shared_mdio.h
new file mode 100644
index 0000000..db6e442
--- /dev/null
+++ b/include/linux/shared_mdio.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#ifndef __SHARED_MDIO_H__
+#define __SHARED_MDIO_H__
+
+#include <linux/device.h>
+#include <linux/types.h>
+
+extern struct bus_type shared_mdio_bus;
+
+/*
+ * This structure represets the mdio master that control the MDIO bus
+ * to access the phy attached on it.
+ * @dev Underlying device for mdio master
+ * @dev_num Unique device number of mdio master
+ * @mdio_write Write callback of mdio master
+ * @mdio_read Read callback for mdio master
+ */
+struct shared_mdio_master {
+ struct device dev;
+ int dev_num;
+ void *priv;
+
+ int (*mdio_write)(struct shared_mdio_master *master,
+ u16 phyid, u16 reg, u16 data);
+ int (*mdio_read)(struct shared_mdio_master *master, u16 phyid, u16 reg);
+};
+#define to_shared_mdio_master(d) \
+ container_of(d, struct shared_mdio_master, dev)
+
+struct shared_mdio_driver {
+ int (*probe)(struct shared_mdio_master *master);
+ int (*remove)(struct shared_mdio_master *master);
+ void (*shutdown)(struct shared_mdio_master *master);
+
+ struct device_driver driver;
+};
+#define to_shared_mdio_driver(d) \
+ container_of(d, struct shared_mdio_driver, driver)
+
+struct shared_mdio_master *shared_mdio_alloc_master(struct device *parent,
+ struct device_node *node);
+
+int shared_mdio_add_master(struct shared_mdio_master *master);
+
+static inline void shared_mdio_remove_master(struct shared_mdio_master *master)
+{
+ device_unregister(&master->dev);
+}
+
+int __shared_mdio_register_driver(struct shared_mdio_driver *drv,
+ struct module *owner);
+
+/* use a define to avoid include chaining to get THIS_MODULE & friends */
+#define shared_mdio_register_driver(drv) \
+ __shared_mdio_register_driver(drv, THIS_MODULE)
+
+static inline void shared_mdio_unregister_driver(
+ struct shared_mdio_driver *drv)
+{
+ driver_unregister(&drv->driver);
+}
+
+/**
+ * module_shared_mdio_driver() - Helper macro for registering a shared_mdio
+ * driver
+ * @__shared_mdio_driver: shared_mdio_driver struct
+ *
+ * Helper macro for shared mdio drivers which do not do anything special in
+ * module init/exit. This eliminates a lot of boilerplate. Each module
+ * may only use this macro once, and calling it replaces module_init()
+ * and module_exit().
+ */
+#define module_shared_mdio_driver(__shared_mdio_driver) \
+ module_driver(__shared_mdio_driver, shared_mdio_register_driver, \
+ shared_mdio_unregister_driver)
+
+
+static inline int shared_mdio_write(struct shared_mdio_master *master,
+ u16 phy, u16 reg, u16 data)
+{
+ if (master->mdio_write)
+ return master->mdio_write(master, phy, reg, data);
+
+ return -ENOTSUPP;
+}
+
+static inline int shared_mdio_read(struct shared_mdio_master *master,
+ u16 phy_id, u16 reg)
+{
+ if (master->mdio_read)
+ return master->mdio_read(master, phy_id, reg);
+
+ return -ENOTSUPP;
+}
+
+/*
+ * Use the following functions to manipulate shared_mdio's per-master
+ * driver-specific data.
+ */
+static inline void *shared_mdio_get_drvdata(struct shared_mdio_master *master)
+{
+ return dev_get_drvdata(&master->dev);
+}
+
+static inline void shared_mdio_set_drvdata(struct shared_mdio_master *master,
+ void *data)
+{
+ dev_set_drvdata(&master->dev, data);
+}
+
+#endif
--
1.9.1
^ permalink raw reply related
* [PATCH 2/6] Documentation: DT binding doc for iProc Shared MDIO Controller.
From: Pramod Kumar @ 2016-04-21 9:18 UTC (permalink / raw)
To: Rob Herring, Catalin Marinas, Will Deacon, Masahiro Yamada,
Chen-Yu Tsai
Cc: BCM Kernel Feedback, Pawel Moll, Mark Rutland, Arnd Bergmann,
Suzuki K Poulose, Punit Agrawal, devicetree, linux-arm-kernel,
linux-kernel, netdev, Pramod Kumar
In-Reply-To: <1461230323-27891-1-git-send-email-pramod.kumar@broadcom.com>
Add DT binding doc for iProc Shared MDIO Controller which
populate all masters to Shared MDIO framework.
Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
---
.../bindings/bus/brcm,iproc-shared-mdio.txt | 76 ++++++++++++++++++++++
1 file changed, 76 insertions(+)
create mode 100644 Documentation/devicetree/bindings/bus/brcm,iproc-shared-mdio.txt
diff --git a/Documentation/devicetree/bindings/bus/brcm,iproc-shared-mdio.txt b/Documentation/devicetree/bindings/bus/brcm,iproc-shared-mdio.txt
new file mode 100644
index 0000000..f455f3d
--- /dev/null
+++ b/Documentation/devicetree/bindings/bus/brcm,iproc-shared-mdio.txt
@@ -0,0 +1,76 @@
+Broadcom iProc Shared MDIO Controller
+
+Required properties:
+- compatible:
+ "brcm,iproc-shared-mdio" for shared MDIO controller.
+- reg: specifies the base physical address and size of the registers
+- reg-names: should be "mdio"
+- #address-cells: must be 1.
+- #size-cells: must be 0.
+
+optional:
+child nodes: Masters are represented as a child node of shared MDIO controller
+and all the PHYs handled by this master are represented as its child node.
+
+Master nodes properties are defined as-
+
+Required properties:
+- compatible: Used to match driver of this PHY.
+- reg: MDIO master ID.
+- #address-cells: must be 1.
+- #size-cells: must be 0.
+
+optional:
+-brcm,phy-internal: if presents, PHYs are internal. Absence shows phy is
+external.
+-brcm,is-c45: if presents, Controller uses Clause-45 to issue MDIO transaction.
+else Controller uses Clause-22 for transactions.
+
+PHY nodes are represented as the child node of Master. Child nodes properties
+are defined as-
+
+Required properties:
+-reg: phy id of attached PHY.
+
+optional:
+There could be additional properties required to configure the specific phy like
+phy-mode in case of gpphy node below. These should be defined here and used by
+respective drivers.
+
+Example:
+iproc_mdio: iproc_mdio@663f0000 {
+ compatible = "brcm,iproc-shared-mdio";
+ reg = <0x6602023c 0x14>;
+ reg-names = "mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+
+ sata-master@6 {
+ compatible = "brcm,iproc-ns2-sata-phy";
+ reg = <0x6>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ brcm,phy-internal;
+
+ sata_phy0: sata-phy@1 {
+ reg = <0x1>;
+ #phy-cells = <0>;
+ };
+
+ sata_phy1: sata-phy@2 {
+ reg = <0x2>;
+ #phy-cells = <0>;
+ };
+ };
+
+ eth-master@0 {
+ compatible = "brcm,iproc-mdio-master-eth";
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gphy0: eth-phy@10 {
+ reg = <0x10>;
+ phy-mode = "mii";
+ };
+ };
+};
--
1.9.1
^ permalink raw reply related
* [PATCH 3/6] bus: Add platform driver for iProc shared MDIO Controller
From: Pramod Kumar @ 2016-04-21 9:18 UTC (permalink / raw)
To: Rob Herring, Catalin Marinas, Will Deacon, Masahiro Yamada,
Chen-Yu Tsai
Cc: BCM Kernel Feedback, Pawel Moll, Mark Rutland, Arnd Bergmann,
Suzuki K Poulose, Punit Agrawal, devicetree, linux-arm-kernel,
linux-kernel, netdev, Pramod Kumar
In-Reply-To: <1461230323-27891-1-git-send-email-pramod.kumar@broadcom.com>
Add platform driver to populate shared MDIO masters on iProc SoC.
Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
Reviewed-by: Anup Patel <anup.patel@broadcom.com>
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
Reviewed-by: Vikram Prakash <vikram.prakash@broadcom.com>
---
drivers/bus/Kconfig | 11 ++
drivers/bus/Makefile | 1 +
drivers/bus/iproc_shared_mdio.c | 287 ++++++++++++++++++++++++++++++++++++++++
3 files changed, 299 insertions(+)
create mode 100644 drivers/bus/iproc_shared_mdio.c
diff --git a/drivers/bus/Kconfig b/drivers/bus/Kconfig
index 1b51b1a..c3f2cb9 100644
--- a/drivers/bus/Kconfig
+++ b/drivers/bus/Kconfig
@@ -118,6 +118,17 @@ config SHARED_MDIO
Respective drivers would be called matching a compatible string
provided in master node.
+config IPROC_SHARED_MDIO
+ tristate "iProc Shared MDIO Driver"
+ depends on OF
+ select SHARED_MDIO
+ default ARCH_BCM_IPROC
+ help
+ Platform driver for shared MDIO controller. Broadcom's iProc based
+ SoCs have many masters which uses one shared bus to accessed its PHY.
+ This platform driver populates all master to Shared bus and provide
+ the MDIO controller specific implementation.
+
config SIMPLE_PM_BUS
bool "Simple Power-Managed Bus Driver"
depends on OF && PM
diff --git a/drivers/bus/Makefile b/drivers/bus/Makefile
index 2b6d6e9..3e364da 100644
--- a/drivers/bus/Makefile
+++ b/drivers/bus/Makefile
@@ -20,3 +20,4 @@ obj-$(CONFIG_SIMPLE_PM_BUS) += simple-pm-bus.o
obj-$(CONFIG_UNIPHIER_SYSTEM_BUS) += uniphier-system-bus.o
obj-$(CONFIG_VEXPRESS_CONFIG) += vexpress-config.o
obj-$(CONFIG_SHARED_MDIO) += shared_mdio.o
+obj-$(CONFIG_IPROC_SHARED_MDIO) += iproc_shared_mdio.o
diff --git a/drivers/bus/iproc_shared_mdio.c b/drivers/bus/iproc_shared_mdio.c
new file mode 100644
index 0000000..af232eb
--- /dev/null
+++ b/drivers/bus/iproc_shared_mdio.c
@@ -0,0 +1,287 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * Platform driver for Shared MDIO Masters on iProc SoC
+ */
+
+#include <linux/io.h>
+#include <linux/module.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/shared_mdio.h>
+#include <linux/mutex.h>
+#include <linux/delay.h>
+
+struct shared_mdio_master_param {
+ bool is_internal;
+ bool is_c45;
+ unsigned int master_id;
+};
+
+struct iproc_shared_mdio {
+ struct device *dev;
+ struct mutex lock;
+ void __iomem *regs;
+ unsigned int num_masters;
+ struct shared_mdio_master **masters;
+};
+
+#define PHY_INTERNAL 1
+#define CLAUSE_45 1
+
+#define MDIO_PARAM_OFFSET 0x00
+#define MDIO_PARAM_MIIM_CYCLE 29
+#define MDIO_PARAM_INTERNAL_SEL 25
+#define MDIO_PARAM_BUS_ID 22
+#define MDIO_PARAM_C45_SEL 21
+#define MDIO_PARAM_PHY_ID 16
+#define MDIO_PARAM_PHY_DATA 0
+
+#define MDIO_READ_OFFSET 0x04
+#define MDIO_READ_DATA_MASK 0xffff
+#define MDIO_ADDR_OFFSET 0x08
+
+#define MDIO_CTRL_OFFSET 0x0C
+#define MDIO_CTRL_WRITE_OP 0x1
+#define MDIO_CTRL_READ_OP 0x2
+
+#define MDIO_STAT_OFFSET 0x10
+#define MDIO_STAT_DONE 1
+
+static int iproc_mdio_wait_for_idle(void __iomem *base, bool result)
+{
+ u32 val;
+ unsigned int timeout = 1000; /* loop for 1s */
+
+ do {
+ val = readl(base + MDIO_STAT_OFFSET);
+ if ((val & MDIO_STAT_DONE) == result)
+ return 0;
+
+ usleep_range(1000, 2000);
+ } while (timeout--);
+
+ return -ETIMEDOUT;
+}
+
+static inline u32 get_cmd(bool con, u16 mid, bool is_c45, u16 phyid, u16 val)
+{
+ u32 cmd;
+
+ cmd = (con ? 1 : 0) << MDIO_PARAM_INTERNAL_SEL;
+ cmd |= mid << MDIO_PARAM_BUS_ID;
+ cmd |= (is_c45 ? 1 : 0) << MDIO_PARAM_C45_SEL;
+ cmd |= phyid << MDIO_PARAM_PHY_ID;
+ cmd |= val << MDIO_PARAM_PHY_DATA;
+
+ return cmd;
+}
+
+/*
+ * start_miim_ops- Program and start MDIO transaction over mdio bus.
+ * @base: Base address
+ * @cmd: param values that need to be programmed in MDIO PARAM_OFFSET.
+ * @reg: register offset ot be read/written.
+ * @op: Operation that need to be carried out.
+ * MDIO_CTRL_READ_OP: Read transaction.
+ * MDIO_CTRL_WRITE_OP: Write transaction.
+ *
+ * Return value: Sucessfull Read operation returns read reg values and write
+ * operation returns 0. Failure opertation returns negative error code.
+ */
+static int start_miim_ops(void __iomem *base, u32 cmd, u32 reg, u32 op)
+{
+ int ret = 0;
+
+ writel(0, base + MDIO_CTRL_OFFSET);
+ ret = iproc_mdio_wait_for_idle(base, false);
+ if (ret)
+ return ret;
+
+ writel(cmd, base + MDIO_PARAM_OFFSET);
+ writel(reg, base + MDIO_ADDR_OFFSET);
+
+ writel(op, base + MDIO_CTRL_OFFSET);
+
+ ret = iproc_mdio_wait_for_idle(base, true);
+ if (ret)
+ return ret;
+
+ if (op == MDIO_CTRL_READ_OP)
+ ret = readl(base + MDIO_READ_OFFSET) & MDIO_READ_DATA_MASK;
+
+ return ret;
+}
+
+static int iproc_shared_mdio_read(struct shared_mdio_master *master,
+ u16 phyid, u16 reg)
+{
+ int ret;
+ u32 cmd;
+ struct iproc_shared_mdio *imdio = dev_get_drvdata(master->dev.parent);
+ struct shared_mdio_master_param *param = master->priv;
+
+ mutex_lock(&imdio->lock);
+
+ dev_dbg(imdio->dev, "master=%d phy=%d reg=%d\n",
+ param->master_id, phyid, reg);
+
+ cmd = get_cmd(param->is_internal, param->master_id, param->is_c45,
+ phyid, 0x0);
+ ret = start_miim_ops(imdio->regs, cmd, reg, MDIO_CTRL_READ_OP);
+ if (ret < 0)
+ dev_err(imdio->dev, "MDIO read operation failed!!!");
+
+ mutex_unlock(&imdio->lock);
+ return ret;
+}
+
+static int iproc_shared_mdio_write(struct shared_mdio_master *master,
+ u16 phyid, u16 reg, u16 val)
+{
+ u32 cmd;
+ int ret;
+ struct iproc_shared_mdio *imdio = dev_get_drvdata(master->dev.parent);
+ struct shared_mdio_master_param *param = master->priv;
+
+ mutex_lock(&imdio->lock);
+
+ dev_dbg(imdio->dev, "master=%d phy=%d reg=%d val=0x%x\n",
+ param->master_id, phyid, reg, val);
+
+ /* Write val at reg offset */
+ cmd = get_cmd(param->is_internal, param->master_id, param->is_c45,
+ phyid, val);
+ ret = start_miim_ops(imdio->regs, cmd, reg, MDIO_CTRL_WRITE_OP);
+ if (ret < 0)
+ dev_err(imdio->dev, "MDIO Write operation failed!!!");
+
+ mutex_unlock(&imdio->lock);
+ return ret;
+}
+
+static int iproc_shared_mdio_probe(struct platform_device *pdev)
+{
+ struct device *dev = &pdev->dev;
+ struct device_node *dn = dev->of_node, *child;
+ struct iproc_shared_mdio *imdio;
+ struct resource *res;
+ int ret = 0, cnt;
+
+ imdio = devm_kzalloc(dev, sizeof(*imdio), GFP_KERNEL);
+ if (!imdio)
+ return -ENOMEM;
+
+ imdio->num_masters = of_get_available_child_count(dn);
+ if (!imdio->num_masters)
+ return -ENODEV;
+
+ imdio->masters = devm_kcalloc(dev, imdio->num_masters,
+ sizeof(**imdio->masters), GFP_KERNEL);
+ if (!imdio->masters)
+ return -ENOMEM;
+
+ res = platform_get_resource_byname(pdev, IORESOURCE_MEM, "mdio");
+ imdio->regs = devm_ioremap_resource(dev, res);
+ if (IS_ERR(imdio->regs))
+ return PTR_ERR(imdio->regs);
+
+ imdio->dev = dev;
+ mutex_init(&imdio->lock);
+
+ cnt = 0;
+ for_each_available_child_of_node(dn, child) {
+ unsigned int id;
+ struct shared_mdio_master *master;
+ struct shared_mdio_master_param *param;
+
+ if (of_property_read_u32(child, "reg", &id)) {
+ dev_err(dev, "missing reg property in node %s\n",
+ child->name);
+ ret = -EINVAL;
+ goto fail;
+ }
+
+ master = shared_mdio_alloc_master(dev, child);
+ if (IS_ERR(master)) {
+ ret = PTR_ERR(master);
+ goto fail;
+ }
+ imdio->masters[cnt] = master;
+
+ param = devm_kzalloc(dev, sizeof(*param), GFP_KERNEL);
+ if (!param) {
+ ret = -ENOMEM;
+ goto fail;
+ }
+ master->priv = param;
+ param->master_id = id;
+
+ param->is_internal = of_property_read_bool(child,
+ "brcm,phy-internal");
+ param->is_c45 = of_property_read_bool(child, "brcm,is-c45");
+ master->mdio_read = iproc_shared_mdio_read;
+ master->mdio_write = iproc_shared_mdio_write;
+
+ ret = shared_mdio_add_master(master);
+ if (ret)
+ goto fail;
+ cnt++;
+ }
+ platform_set_drvdata(pdev, imdio);
+ dev_info(dev, "registered %d masters(s)\n", cnt);
+ return 0;
+fail:
+ for (cnt = 0; cnt < imdio->num_masters; cnt++) {
+ if (imdio->masters[cnt]) {
+ shared_mdio_remove_master(imdio->masters[cnt]);
+ imdio->masters[cnt] = NULL;
+ }
+ }
+ return ret;
+}
+
+static int iproc_shared_mdio_remove(struct platform_device *pdev)
+{
+ int i;
+ struct iproc_shared_mdio *imdio = platform_get_drvdata(pdev);
+
+ for (i = 0; i < imdio->num_masters; i++) {
+ if (imdio->masters[i]) {
+ shared_mdio_remove_master(imdio->masters[i]);
+ imdio->masters[i] = NULL;
+ }
+ }
+
+ return 0;
+}
+
+static const struct of_device_id iproc_shared_mdio_of_match[] = {
+ { .compatible = "brcm,iproc-shared-mdio", },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, iproc_shared_mdio_of_match);
+
+static struct platform_driver iproc_shared_mdio_driver = {
+ .probe = iproc_shared_mdio_probe,
+ .remove = iproc_shared_mdio_remove,
+ .driver = {
+ .name = "iproc-shared-mdio",
+ .of_match_table = iproc_shared_mdio_of_match,
+ },
+};
+
+module_platform_driver(iproc_shared_mdio_driver);
+
+MODULE_DESCRIPTION("iProc Shared MDIO Master Driver");
+MODULE_AUTHOR("Pramod Kumar <pramod.kumar@broadcom.com>");
+MODULE_LICENSE("GPL v2");
--
1.9.1
^ permalink raw reply related
* [PATCH 4/6] dt: Add Shared MDIO Controller node for NS2
From: Pramod Kumar @ 2016-04-21 9:18 UTC (permalink / raw)
To: Rob Herring, Catalin Marinas, Will Deacon, Masahiro Yamada,
Chen-Yu Tsai
Cc: BCM Kernel Feedback, Pawel Moll, Mark Rutland, Arnd Bergmann,
Suzuki K Poulose, Punit Agrawal, devicetree, linux-arm-kernel,
linux-kernel, netdev, Pramod Kumar
In-Reply-To: <1461230323-27891-1-git-send-email-pramod.kumar@broadcom.com>
Add NS2 Shared MDIO Controller DT node having eth phy as child.
This node represents the NS2 AMAC eth phy.
Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
---
arch/arm64/boot/dts/broadcom/ns2-svk.dts | 15 +++++++++++++++
arch/arm64/boot/dts/broadcom/ns2.dtsi | 8 ++++++++
2 files changed, 23 insertions(+)
diff --git a/arch/arm64/boot/dts/broadcom/ns2-svk.dts b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
index ce0ab84..2944418 100644
--- a/arch/arm64/boot/dts/broadcom/ns2-svk.dts
+++ b/arch/arm64/boot/dts/broadcom/ns2-svk.dts
@@ -87,3 +87,18 @@
#size-cells = <1>;
};
};
+
+&iproc_shared_mdio {
+ eth-master@0 {
+ compatible = "brcm,iproc-mdio-master-eth";
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ status = "ok";
+
+ gphy0: eth-phy@10 {
+ reg = <0x10>;
+ phy-mode = "mii";
+ };
+ };
+};
diff --git a/arch/arm64/boot/dts/broadcom/ns2.dtsi b/arch/arm64/boot/dts/broadcom/ns2.dtsi
index 6f81c9d..5b98c81 100644
--- a/arch/arm64/boot/dts/broadcom/ns2.dtsi
+++ b/arch/arm64/boot/dts/broadcom/ns2.dtsi
@@ -330,6 +330,14 @@
<0x65260000 0x1000>;
};
+ iproc_shared_mdio: iproc_shared_mdio@6602023c {
+ compatible = "brcm,iproc-shared-mdio";
+ reg = <0x6602023c 0x14>;
+ reg-names = "mdio";
+ #address-cells = <1>;
+ #size-cells = <0>;
+ };
+
timer0: timer@66030000 {
compatible = "arm,sp804", "arm,primecell";
reg = <0x66030000 0x1000>;
--
1.9.1
^ permalink raw reply related
* [PATCH 5/6] Documentation: Binding doc for ethernet master in NS2
From: Pramod Kumar @ 2016-04-21 9:18 UTC (permalink / raw)
To: Rob Herring, Catalin Marinas, Will Deacon, Masahiro Yamada,
Chen-Yu Tsai
Cc: Mark Rutland, devicetree, Pawel Moll, Arnd Bergmann,
Suzuki K Poulose, netdev, Punit Agrawal, linux-kernel,
Pramod Kumar, BCM Kernel Feedback, linux-arm-kernel
In-Reply-To: <1461230323-27891-1-git-send-email-pramod.kumar@broadcom.com>
Adding binding doc for ethernet master present in shared
MDIO controller.
Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
---
.../bindings/net/brcm,iproc-mdio-shared.txt | 32 ++++++++++++++++++++++
1 file changed, 32 insertions(+)
create mode 100644 Documentation/devicetree/bindings/net/brcm,iproc-mdio-shared.txt
diff --git a/Documentation/devicetree/bindings/net/brcm,iproc-mdio-shared.txt b/Documentation/devicetree/bindings/net/brcm,iproc-mdio-shared.txt
new file mode 100644
index 0000000..1ffdd4b
--- /dev/null
+++ b/Documentation/devicetree/bindings/net/brcm,iproc-mdio-shared.txt
@@ -0,0 +1,32 @@
+Broadcom Ethernet master for shared mdio controller
+
+Required properties:
+- compatible: must be "brcm,iproc-mdio-master-eth"
+- reg: master id of Ethernet block
+- address-cells: should be 1
+- size-cells: should be 0
+
+Sub-nodes:
+ Each port's PHY should be represented as a sub-node.
+
+Sub-nodes required properties:
+- reg: the PHY number
+- phy-mode: media type connecting the PHY and MAC.
+
+
+Example:
+ eth-master@0 {
+ compatible = "brcm,iproc-mdio-master-eth";
+ reg = <0x0>;
+ #address-cells = <1>;
+ #size-cells = <0>;
+ gphy0: eth-phy@10 {
+ reg = <0x10>;
+ phy-mode = "mii";
+ };
+ status = "ok"
+ };
+
+For more info on ethernet phy binding, please,refer to:
+Documentation/devicetree/bindings/net/phy.txt
+Documentation/devicetree/bindings/net/ethernet.txt
--
1.9.1
^ permalink raw reply related
* [PATCH 6/6] net:phy: Add Ethernet Master for iProc Shared MDIO Controller
From: Pramod Kumar @ 2016-04-21 9:18 UTC (permalink / raw)
To: Rob Herring, Catalin Marinas, Will Deacon, Masahiro Yamada,
Chen-Yu Tsai
Cc: Mark Rutland, devicetree, Pawel Moll, Arnd Bergmann,
Suzuki K Poulose, netdev, Punit Agrawal, linux-kernel,
Pramod Kumar, BCM Kernel Feedback, linux-arm-kernel
In-Reply-To: <1461230323-27891-1-git-send-email-pramod.kumar@broadcom.com>
Add Ethernet master driver which registers the ethernet phy
to standard legacy mdio framework.
Signed-off-by: Pramod Kumar <pramod.kumar@broadcom.com>
Reviewed-by: Ray Jui <ray.jui@broadcom.com>
Reviewed-by: Scott Branden <scott.branden@broadcom.com>
---
drivers/net/phy/Kconfig | 11 +++
drivers/net/phy/Makefile | 1 +
drivers/net/phy/mdio-bcm-iproc-shared.c | 116 ++++++++++++++++++++++++++++++++
3 files changed, 128 insertions(+)
create mode 100644 drivers/net/phy/mdio-bcm-iproc-shared.c
diff --git a/drivers/net/phy/Kconfig b/drivers/net/phy/Kconfig
index 6dad9a9..35a7d59 100644
--- a/drivers/net/phy/Kconfig
+++ b/drivers/net/phy/Kconfig
@@ -271,6 +271,17 @@ config MDIO_BCM_IPROC
This module provides a driver for the MDIO busses found in the
Broadcom iProc SoC's.
+config MDIO_BCM_IPROC_SHARED
+ tristate "Ethernet Master for Broadcom iProc Shared MDIO Controller"
+ depends on OF && OF_MDIO && (ARCH_BCM_IPROC || COMPILE_TEST)
+ default ARCH_BCM_IPROC
+ help
+ This module provides a driver for the ethernet master found in
+ shared MDIO controller in the Broadcom iProc SoC's.
+
+ Enable this to support the Shared MDIO controller.
+ if unsure, say N.
+
endif # PHYLIB
config MICREL_KS8995MA
diff --git a/drivers/net/phy/Makefile b/drivers/net/phy/Makefile
index fcdbb92..e1c0bc5 100644
--- a/drivers/net/phy/Makefile
+++ b/drivers/net/phy/Makefile
@@ -44,3 +44,4 @@ obj-$(CONFIG_MDIO_MOXART) += mdio-moxart.o
obj-$(CONFIG_MDIO_BCM_UNIMAC) += mdio-bcm-unimac.o
obj-$(CONFIG_MICROCHIP_PHY) += microchip.o
obj-$(CONFIG_MDIO_BCM_IPROC) += mdio-bcm-iproc.o
+obj-$(CONFIG_MDIO_BCM_IPROC_SHARED) += mdio-bcm-iproc-shared.o
diff --git a/drivers/net/phy/mdio-bcm-iproc-shared.c b/drivers/net/phy/mdio-bcm-iproc-shared.c
new file mode 100644
index 0000000..6844107
--- /dev/null
+++ b/drivers/net/phy/mdio-bcm-iproc-shared.c
@@ -0,0 +1,116 @@
+/*
+ * Copyright (C) 2016 Broadcom
+ *
+ * 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.
+ *
+ * This program is distributed "as is" WITHOUT ANY WARRANTY of any
+ * kind, whether express or implied; without even the implied warranty
+ * of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/of.h>
+#include <linux/shared_mdio.h>
+#include <linux/io.h>
+#include <linux/phy.h>
+#include <linux/of_mdio.h>
+
+struct iproc_mdio_priv {
+ struct shared_mdio_master *master;
+ struct mii_bus *mii_bus;
+};
+
+static int iproc_mdio_mii_read(struct mii_bus *bus, int phyadr, int reg)
+{
+ struct iproc_mdio_priv *priv = (struct iproc_mdio_priv *)bus->priv;
+
+ return shared_mdio_read(priv->master, phyadr, reg);
+}
+
+static int iproc_mdio_mii_write(struct mii_bus *bus, int phyadr, int reg,
+ u16 val)
+{
+ struct iproc_mdio_priv *priv = bus->priv;
+
+ return shared_mdio_write(priv->master, phyadr, reg, val);
+}
+
+static int iproc_mdio_probe(struct shared_mdio_master *master)
+{
+ struct device *dev = &master->dev;
+ struct iproc_mdio_priv *priv;
+ struct mii_bus *bus;
+ struct device_node *dn = dev->of_node;
+ int rc = 0;
+
+ if (of_get_child_count(dn) == 0)
+ return -ENODEV;
+
+ priv = devm_kzalloc(dev, sizeof(*priv), GFP_KERNEL);
+ if (!priv)
+ return -ENOMEM;
+ priv->master = master;
+
+ priv->mii_bus = mdiobus_alloc();
+ if (!priv->mii_bus) {
+ dev_err(dev, "mdio bus alloc failed\n");
+ return -ENOMEM;
+ }
+
+ bus = priv->mii_bus;
+ bus->priv = priv;
+ bus->name = "iProc MDIO bus";
+ snprintf(bus->id, MII_BUS_ID_SIZE, "%s-%d", dev_name(&master->dev),
+ master->dev_num);
+ bus->parent = &master->dev;
+ bus->read = iproc_mdio_mii_read;
+ bus->write = iproc_mdio_mii_write;
+
+ rc = of_mdiobus_register(bus, master->dev.of_node);
+ if (rc) {
+ dev_err(dev, "mdio bus registration failed\n");
+ goto mdiobus_err;
+ }
+
+ shared_mdio_set_drvdata(master, priv);
+ dev_info(dev, "iProc MDIO bus registered\n");
+ return 0;
+
+mdiobus_err:
+ mdiobus_free(bus);
+ return rc;
+}
+
+int iproc_mdio_remove(struct shared_mdio_master *master)
+{
+ struct iproc_mdio_priv *priv = shared_mdio_get_drvdata(master);
+
+ mdiobus_unregister(priv->mii_bus);
+ mdiobus_free(priv->mii_bus);
+
+ return 0;
+}
+
+static const struct of_device_id iproc_mdio_of_match[] = {
+ { .compatible = "brcm,iproc-mdio-master-eth" },
+ { /* sentinel */ }
+};
+MODULE_DEVICE_TABLE(of, iproc_mdio_of_match);
+
+static struct shared_mdio_driver iproc_mdio_driver = {
+ .driver = {
+ .name = "iproc-mdio-master-eth",
+ .of_match_table = iproc_mdio_of_match,
+ },
+ .probe = iproc_mdio_probe,
+ .remove = iproc_mdio_remove,
+};
+module_shared_mdio_driver(iproc_mdio_driver);
+
+MODULE_DESCRIPTION("Broadcom iProc shared mdio master driver");
+MODULE_LICENSE("GPL v2");
+MODULE_AUTHOR("Pramod Kumar <pramod.kumar@broadcom.com>");
--
1.9.1
^ permalink raw reply related
* [PATCH v2] MAINTAINERS: net: add entry for TI Ethernet Switch drivers
From: Grygorii Strashko @ 2016-04-21 10:13 UTC (permalink / raw)
To: netdev, linux-kernel, David S. Miller
Cc: Sekhar Nori, linux-omap, Grygorii Strashko, Tony Lindgren,
Mugunthan V N, Richard Cochran
Add record for TI Ethernet Switch Driver CPSW/CPDMA/MDIO HW
(am33/am43/am57/dr7/davinci) to ensure that related patches
will go through dedicated linux-omap list.
Also add Mugunthan as maintainer and myself as the reviewer.
Cc: "David S. Miller" <davem@davemloft.net>
Cc: Tony Lindgren <tony@atomide.com>
Cc: Mugunthan V N <mugunthanvnm@ti.com>
Cc: Richard Cochran <richardcochran@gmail.com>
Signed-off-by: Grygorii Strashko <grygorii.strashko@ti.com>
---
Changes in v2:
- added netdev@vger.kernel.org list
MAINTAINERS | 9 +++++++++
1 file changed, 9 insertions(+)
diff --git a/MAINTAINERS b/MAINTAINERS
index 1d5b4be..8491336 100644
--- a/MAINTAINERS
+++ b/MAINTAINERS
@@ -11071,6 +11071,15 @@ S: Maintained
F: drivers/clk/ti/
F: include/linux/clk/ti.h
+TI ETHERNET SWITCH DRIVER (CPSW)
+M: Mugunthan V N <mugunthanvnm@ti.com>
+R: Grygorii Strashko <grygorii.strashko@ti.com>
+L: linux-omap@vger.kernel.org
+L: netdev@vger.kernel.org
+S: Maintained
+F: drivers/net/ethernet/ti/cpsw*
+F: drivers/net/ethernet/ti/davinci*
+
TI FLASH MEDIA INTERFACE DRIVER
M: Alex Dubov <oakad@yahoo.com>
S: Maintained
--
2.8.1
^ permalink raw reply related
* [patch net 0/3] bridge: mdb: Couple of fixes
From: Jiri Pirko @ 2016-04-21 10:52 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, eladr, yotamg, ogerlitz, stephen, nikolay
From: Jiri Pirko <jiri@mellanox.com>
Elad says:
This patchset fixes two problems reported by Nikolay Aleksandrov. The first
problem is that the MDB offload flag might be accesed without helding the
multicast_lock.
The second problem is that the switchdev mdb offload is deferred and
the offload bit was marked regardless if the operation succeeded or not.
Elad Raz (3):
switchdev: Adding complete operation to deferred switchdev ops
bridge: mdb: Common function for mdb entry translation
bridge: mdb: Marking port-group as offloaded
include/net/switchdev.h | 4 ++
net/bridge/br_mdb.c | 124 +++++++++++++++++++++++++++++-----------------
net/bridge/br_multicast.c | 8 +--
net/bridge/br_private.h | 4 +-
net/switchdev/switchdev.c | 6 +++
5 files changed, 96 insertions(+), 50 deletions(-)
--
2.5.5
^ permalink raw reply
* [patch net 1/3] switchdev: Adding complete operation to deferred switchdev ops
From: Jiri Pirko @ 2016-04-21 10:52 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, eladr, yotamg, ogerlitz, stephen, nikolay
In-Reply-To: <1461235965-3930-1-git-send-email-jiri@resnulli.us>
From: Elad Raz <eladr@mellanox.com>
When using switchdev deferred operation (SWITCHDEV_F_DEFER), the operation
is executed in different context and the application doesn't have any way
to get the operation real status.
Adding a completion callback fixes that. This patch adds fields to
switchdev_attr and switchdev_obj "complete_priv" field which is used by
the "complete" callback.
Application can set a complete function which will be called once the
operation executed.
Signed-off-by: Elad Raz <eladr@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
---
include/net/switchdev.h | 4 ++++
net/switchdev/switchdev.c | 6 ++++++
2 files changed, 10 insertions(+)
diff --git a/include/net/switchdev.h b/include/net/switchdev.h
index d451122..51d77b2 100644
--- a/include/net/switchdev.h
+++ b/include/net/switchdev.h
@@ -54,6 +54,8 @@ struct switchdev_attr {
struct net_device *orig_dev;
enum switchdev_attr_id id;
u32 flags;
+ void *complete_priv;
+ void (*complete)(struct net_device *dev, int err, void *priv);
union {
struct netdev_phys_item_id ppid; /* PORT_PARENT_ID */
u8 stp_state; /* PORT_STP_STATE */
@@ -75,6 +77,8 @@ struct switchdev_obj {
struct net_device *orig_dev;
enum switchdev_obj_id id;
u32 flags;
+ void *complete_priv;
+ void (*complete)(struct net_device *dev, int err, void *priv);
};
/* SWITCHDEV_OBJ_ID_PORT_VLAN */
diff --git a/net/switchdev/switchdev.c b/net/switchdev/switchdev.c
index 2b9b98f..b7e01d8 100644
--- a/net/switchdev/switchdev.c
+++ b/net/switchdev/switchdev.c
@@ -305,6 +305,8 @@ static void switchdev_port_attr_set_deferred(struct net_device *dev,
if (err && err != -EOPNOTSUPP)
netdev_err(dev, "failed (err=%d) to set attribute (id=%d)\n",
err, attr->id);
+ if (attr->complete)
+ attr->complete(dev, err, attr->complete_priv);
}
static int switchdev_port_attr_set_defer(struct net_device *dev,
@@ -434,6 +436,8 @@ static void switchdev_port_obj_add_deferred(struct net_device *dev,
if (err && err != -EOPNOTSUPP)
netdev_err(dev, "failed (err=%d) to add object (id=%d)\n",
err, obj->id);
+ if (obj->complete)
+ obj->complete(dev, err, obj->complete_priv);
}
static int switchdev_port_obj_add_defer(struct net_device *dev,
@@ -502,6 +506,8 @@ static void switchdev_port_obj_del_deferred(struct net_device *dev,
if (err && err != -EOPNOTSUPP)
netdev_err(dev, "failed (err=%d) to del object (id=%d)\n",
err, obj->id);
+ if (obj->complete)
+ obj->complete(dev, err, obj->complete_priv);
}
static int switchdev_port_obj_del_defer(struct net_device *dev,
--
2.5.5
^ permalink raw reply related
* [patch net 2/3] bridge: mdb: Common function for mdb entry translation
From: Jiri Pirko @ 2016-04-21 10:52 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, eladr, yotamg, ogerlitz, stephen, nikolay
In-Reply-To: <1461235965-3930-1-git-send-email-jiri@resnulli.us>
From: Elad Raz <eladr@mellanox.com>
There is duplicate code that translates br_mdb_entry to br_ip let's wrap it
in a common function.
Signed-off-by: Elad Raz <eladr@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
---
net/bridge/br_mdb.c | 33 +++++++++++++++------------------
1 file changed, 15 insertions(+), 18 deletions(-)
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index 253bc77..b258120 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -61,6 +61,19 @@ static void __mdb_entry_fill_flags(struct br_mdb_entry *e, unsigned char flags)
e->flags |= MDB_FLAGS_OFFLOAD;
}
+static void __mdb_entry_to_br_ip(struct br_mdb_entry *entry, struct br_ip *ip)
+{
+ memset(ip, 0, sizeof(struct br_ip));
+ ip->vid = entry->vid;
+ ip->proto = entry->addr.proto;
+ if (ip->proto == htons(ETH_P_IP))
+ ip->u.ip4 = entry->addr.u.ip4;
+#if IS_ENABLED(CONFIG_IPV6)
+ else
+ ip->u.ip6 = entry->addr.u.ip6;
+#endif
+}
+
static int br_mdb_fill_info(struct sk_buff *skb, struct netlink_callback *cb,
struct net_device *dev)
{
@@ -509,15 +522,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
if (!p || p->br != br || p->state == BR_STATE_DISABLED)
return -EINVAL;
- memset(&ip, 0, sizeof(ip));
- ip.vid = entry->vid;
- ip.proto = entry->addr.proto;
- if (ip.proto == htons(ETH_P_IP))
- ip.u.ip4 = entry->addr.u.ip4;
-#if IS_ENABLED(CONFIG_IPV6)
- else
- ip.u.ip6 = entry->addr.u.ip6;
-#endif
+ __mdb_entry_to_br_ip(entry, &ip);
spin_lock_bh(&br->multicast_lock);
ret = br_mdb_add_group(br, p, &ip, entry->state, pg);
@@ -584,15 +589,7 @@ static int __br_mdb_del(struct net_bridge *br, struct br_mdb_entry *entry)
if (!netif_running(br->dev) || br->multicast_disabled)
return -EINVAL;
- memset(&ip, 0, sizeof(ip));
- ip.vid = entry->vid;
- ip.proto = entry->addr.proto;
- if (ip.proto == htons(ETH_P_IP))
- ip.u.ip4 = entry->addr.u.ip4;
-#if IS_ENABLED(CONFIG_IPV6)
- else
- ip.u.ip6 = entry->addr.u.ip6;
-#endif
+ __mdb_entry_to_br_ip(entry, &ip);
spin_lock_bh(&br->multicast_lock);
mdb = mlock_dereference(br->mdb, br);
--
2.5.5
^ permalink raw reply related
* [patch net 3/3] bridge: mdb: Marking port-group as offloaded
From: Jiri Pirko @ 2016-04-21 10:52 UTC (permalink / raw)
To: netdev; +Cc: davem, idosch, eladr, yotamg, ogerlitz, stephen, nikolay
In-Reply-To: <1461235965-3930-1-git-send-email-jiri@resnulli.us>
From: Elad Raz <eladr@mellanox.com>
There is a race-condition when updating the mdb offload flag without using
the mulicast_lock. This reverts commit 9e8430f8d60d98 ("bridge: mdb:
Passing the port-group pointer to br_mdb module").
This patch marks offloaded MDB entry as "offload" by changing the port-
group flags and marks it as MDB_PG_FLAGS_OFFLOAD.
When switchdev PORT_MDB succeeded and adds a multicast group, a completion
callback is been invoked "br_mdb_complete". The completion function
locks the multicast_lock and finds the right net_bridge_port_group and
marks it as offloaded.
Fixes: 9e8430f8d60d98 ("bridge: mdb: Passing the port-group pointer to br_mdb module")
Reported-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
Signed-off-by: Elad Raz <eladr@mellanox.com>
Signed-off-by: Jiri Pirko <jiri@mellanox.com>
Reviewed-by: Ido Schimmel <idosch@mellanox.com>
Acked-by: Nikolay Aleksandrov <nikolay@cumulusnetworks.com>
---
net/bridge/br_mdb.c | 91 +++++++++++++++++++++++++++++++++--------------
net/bridge/br_multicast.c | 8 +++--
net/bridge/br_private.h | 4 +--
3 files changed, 71 insertions(+), 32 deletions(-)
diff --git a/net/bridge/br_mdb.c b/net/bridge/br_mdb.c
index b258120..7dbc80d 100644
--- a/net/bridge/br_mdb.c
+++ b/net/bridge/br_mdb.c
@@ -256,9 +256,45 @@ static inline size_t rtnl_mdb_nlmsg_size(void)
+ nla_total_size(sizeof(struct br_mdb_entry));
}
-static void __br_mdb_notify(struct net_device *dev, struct br_mdb_entry *entry,
- int type, struct net_bridge_port_group *pg)
+struct br_mdb_complete_info {
+ struct net_bridge_port *port;
+ struct br_ip ip;
+};
+
+static void br_mdb_complete(struct net_device *dev, int err, void *priv)
{
+ struct br_mdb_complete_info *data = priv;
+ struct net_bridge_port_group __rcu **pp;
+ struct net_bridge_port_group *p;
+ struct net_bridge_mdb_htable *mdb;
+ struct net_bridge_mdb_entry *mp;
+ struct net_bridge_port *port = data->port;
+ struct net_bridge *br = port->br;
+
+ if (err)
+ goto err;
+
+ spin_lock_bh(&br->multicast_lock);
+ mdb = mlock_dereference(br->mdb, br);
+ mp = br_mdb_ip_get(mdb, &data->ip);
+ if (!mp)
+ goto out;
+ for (pp = &mp->ports; (p = mlock_dereference(*pp, br)) != NULL;
+ pp = &p->next) {
+ if (p->port != port)
+ continue;
+ p->flags |= MDB_PG_FLAGS_OFFLOAD;
+ }
+out:
+ spin_unlock_bh(&br->multicast_lock);
+err:
+ kfree(priv);
+}
+
+static void __br_mdb_notify(struct net_device *dev, struct net_bridge_port *p,
+ struct br_mdb_entry *entry, int type)
+{
+ struct br_mdb_complete_info *complete_info;
struct switchdev_obj_port_mdb mdb = {
.obj = {
.id = SWITCHDEV_OBJ_ID_PORT_MDB,
@@ -281,9 +317,14 @@ static void __br_mdb_notify(struct net_device *dev, struct br_mdb_entry *entry,
mdb.obj.orig_dev = port_dev;
if (port_dev && type == RTM_NEWMDB) {
- err = switchdev_port_obj_add(port_dev, &mdb.obj);
- if (!err && pg)
- pg->flags |= MDB_PG_FLAGS_OFFLOAD;
+ complete_info = kmalloc(sizeof(*complete_info), GFP_ATOMIC);
+ if (complete_info) {
+ complete_info->port = p;
+ __mdb_entry_to_br_ip(entry, &complete_info->ip);
+ mdb.obj.complete_priv = complete_info;
+ mdb.obj.complete = br_mdb_complete;
+ switchdev_port_obj_add(port_dev, &mdb.obj);
+ }
} else if (port_dev && type == RTM_DELMDB) {
switchdev_port_obj_del(port_dev, &mdb.obj);
}
@@ -304,21 +345,21 @@ errout:
rtnl_set_sk_err(net, RTNLGRP_MDB, err);
}
-void br_mdb_notify(struct net_device *dev, struct net_bridge_port_group *pg,
- int type)
+void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
+ struct br_ip *group, int type, u8 flags)
{
struct br_mdb_entry entry;
memset(&entry, 0, sizeof(entry));
- entry.ifindex = pg->port->dev->ifindex;
- entry.addr.proto = pg->addr.proto;
- entry.addr.u.ip4 = pg->addr.u.ip4;
+ entry.ifindex = port->dev->ifindex;
+ entry.addr.proto = group->proto;
+ entry.addr.u.ip4 = group->u.ip4;
#if IS_ENABLED(CONFIG_IPV6)
- entry.addr.u.ip6 = pg->addr.u.ip6;
+ entry.addr.u.ip6 = group->u.ip6;
#endif
- entry.vid = pg->addr.vid;
- __mdb_entry_fill_flags(&entry, pg->flags);
- __br_mdb_notify(dev, &entry, type, pg);
+ entry.vid = group->vid;
+ __mdb_entry_fill_flags(&entry, flags);
+ __br_mdb_notify(dev, port, &entry, type);
}
static int nlmsg_populate_rtr_fill(struct sk_buff *skb,
@@ -463,8 +504,7 @@ static int br_mdb_parse(struct sk_buff *skb, struct nlmsghdr *nlh,
}
static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
- struct br_ip *group, unsigned char state,
- struct net_bridge_port_group **pg)
+ struct br_ip *group, unsigned char state)
{
struct net_bridge_mdb_entry *mp;
struct net_bridge_port_group *p;
@@ -495,7 +535,6 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
if (unlikely(!p))
return -ENOMEM;
rcu_assign_pointer(*pp, p);
- *pg = p;
if (state == MDB_TEMPORARY)
mod_timer(&p->timer, now + br->multicast_membership_interval);
@@ -503,8 +542,7 @@ static int br_mdb_add_group(struct net_bridge *br, struct net_bridge_port *port,
}
static int __br_mdb_add(struct net *net, struct net_bridge *br,
- struct br_mdb_entry *entry,
- struct net_bridge_port_group **pg)
+ struct br_mdb_entry *entry)
{
struct br_ip ip;
struct net_device *dev;
@@ -525,7 +563,7 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
__mdb_entry_to_br_ip(entry, &ip);
spin_lock_bh(&br->multicast_lock);
- ret = br_mdb_add_group(br, p, &ip, entry->state, pg);
+ ret = br_mdb_add_group(br, p, &ip, entry->state);
spin_unlock_bh(&br->multicast_lock);
return ret;
}
@@ -533,7 +571,6 @@ static int __br_mdb_add(struct net *net, struct net_bridge *br,
static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
{
struct net *net = sock_net(skb->sk);
- struct net_bridge_port_group *pg;
struct net_bridge_vlan_group *vg;
struct net_device *dev, *pdev;
struct br_mdb_entry *entry;
@@ -563,15 +600,15 @@ static int br_mdb_add(struct sk_buff *skb, struct nlmsghdr *nlh)
if (br_vlan_enabled(br) && vg && entry->vid == 0) {
list_for_each_entry(v, &vg->vlan_list, vlist) {
entry->vid = v->vid;
- err = __br_mdb_add(net, br, entry, &pg);
+ err = __br_mdb_add(net, br, entry);
if (err)
break;
- __br_mdb_notify(dev, entry, RTM_NEWMDB, pg);
+ __br_mdb_notify(dev, p, entry, RTM_NEWMDB);
}
} else {
- err = __br_mdb_add(net, br, entry, &pg);
+ err = __br_mdb_add(net, br, entry);
if (!err)
- __br_mdb_notify(dev, entry, RTM_NEWMDB, pg);
+ __br_mdb_notify(dev, p, entry, RTM_NEWMDB);
}
return err;
@@ -659,12 +696,12 @@ static int br_mdb_del(struct sk_buff *skb, struct nlmsghdr *nlh)
entry->vid = v->vid;
err = __br_mdb_del(br, entry);
if (!err)
- __br_mdb_notify(dev, entry, RTM_DELMDB, NULL);
+ __br_mdb_notify(dev, p, entry, RTM_DELMDB);
}
} else {
err = __br_mdb_del(br, entry);
if (!err)
- __br_mdb_notify(dev, entry, RTM_DELMDB, NULL);
+ __br_mdb_notify(dev, p, entry, RTM_DELMDB);
}
return err;
diff --git a/net/bridge/br_multicast.c b/net/bridge/br_multicast.c
index a4c15df..191ea66 100644
--- a/net/bridge/br_multicast.c
+++ b/net/bridge/br_multicast.c
@@ -283,7 +283,8 @@ static void br_multicast_del_pg(struct net_bridge *br,
rcu_assign_pointer(*pp, p->next);
hlist_del_init(&p->mglist);
del_timer(&p->timer);
- br_mdb_notify(br->dev, p, RTM_DELMDB);
+ br_mdb_notify(br->dev, p->port, &pg->addr, RTM_DELMDB,
+ p->flags);
call_rcu_bh(&p->rcu, br_multicast_free_pg);
if (!mp->ports && !mp->mglist &&
@@ -705,7 +706,7 @@ static int br_multicast_add_group(struct net_bridge *br,
if (unlikely(!p))
goto err;
rcu_assign_pointer(*pp, p);
- br_mdb_notify(br->dev, p, RTM_NEWMDB);
+ br_mdb_notify(br->dev, port, group, RTM_NEWMDB, 0);
found:
mod_timer(&p->timer, now + br->multicast_membership_interval);
@@ -1461,7 +1462,8 @@ br_multicast_leave_group(struct net_bridge *br,
hlist_del_init(&p->mglist);
del_timer(&p->timer);
call_rcu_bh(&p->rcu, br_multicast_free_pg);
- br_mdb_notify(br->dev, p, RTM_DELMDB);
+ br_mdb_notify(br->dev, port, group, RTM_DELMDB,
+ p->flags);
if (!mp->ports && !mp->mglist &&
netif_running(br->dev))
diff --git a/net/bridge/br_private.h b/net/bridge/br_private.h
index 1b5d145..d9da857 100644
--- a/net/bridge/br_private.h
+++ b/net/bridge/br_private.h
@@ -560,8 +560,8 @@ br_multicast_new_port_group(struct net_bridge_port *port, struct br_ip *group,
unsigned char flags);
void br_mdb_init(void);
void br_mdb_uninit(void);
-void br_mdb_notify(struct net_device *dev, struct net_bridge_port_group *pg,
- int type);
+void br_mdb_notify(struct net_device *dev, struct net_bridge_port *port,
+ struct br_ip *group, int type, u8 flags);
void br_rtr_notify(struct net_device *dev, struct net_bridge_port *port,
int type);
--
2.5.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