* Re: [Bonding-devel] [PATCH] net, bonding: Add return statement in bond_create_proc_entry.
From: Nicolas de Pesloüan @ 2009-10-10 19:19 UTC (permalink / raw)
To: Rakib Mullick
Cc: Jay Vosburgh, netdev, linux-kernel, Andrew Morton, bonding-devel
In-Reply-To: <b9df5fa10910091910u1b6bf14bg2781cb12c58b21f9@mail.gmail.com>
Rakib Mullick wrote:
> The function bond_create_proc_entry supposed to return int instead of void.
> And fixes the following compilation warning.
>
> drivers/net/bonding/bond_main.c: In function `bond_create_proc_entry':
> drivers/net/bonding/bond_main.c:3393: warning: control reaches end of
> non-void function
>
> ---
> Signed-off-by: Rakib Mullick <rakib.mullick@gmail.com>
>
> --- linus/drivers/net/bonding/bond_main.c 2009-10-09 17:38:35.000000000 +0600
> +++ rakib/drivers/net/bonding/bond_main.c 2009-10-09 17:47:46.000000000 +0600
> @@ -3391,6 +3391,7 @@ static void bond_destroy_proc_dir(void)
>
> static int bond_create_proc_entry(struct bonding *bond)
> {
> + return 0;
> }
This empty function is defined inside the else branch of an ifdef. The corresponding non-empty
function always return 0 and no caller of this function use the returned value.
So I suggest to change the return type of this function from int to void, instead of adding a return
0 into the empty one.
Nicolas.
^ permalink raw reply
* [net-next PATCH 0/8] qlge: Cleanup and additions for qlge.
From: Ron Mercer @ 2009-10-10 19:35 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
Cleanup and a couple of small performance tweeks for qlge.
^ permalink raw reply
* [net-next PATCH 1/8] qlge: Remove explicit setting of PCI Dev CTL reg.
From: Ron Mercer @ 2009-10-10 19:35 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer, root
In-Reply-To: <1255203310-18114-1-git-send-email-ron.mercer@qlogic.com>
From: root <root@localhost.localdomain>
Remove explicit setting of error reporting bits.
Signed-off-by: root <root@localhost.localdomain>
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_main.c | 16 +---------------
1 files changed, 1 insertions(+), 15 deletions(-)
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 48b45df..7a9dca8 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -3868,8 +3868,7 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
struct net_device *ndev, int cards_found)
{
struct ql_adapter *qdev = netdev_priv(ndev);
- int pos, err = 0;
- u16 val16;
+ int err = 0;
memset((void *)qdev, 0, sizeof(*qdev));
err = pci_enable_device(pdev);
@@ -3881,19 +3880,6 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
qdev->ndev = ndev;
qdev->pdev = pdev;
pci_set_drvdata(pdev, ndev);
- pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
- if (pos <= 0) {
- dev_err(&pdev->dev, PFX "Cannot find PCI Express capability, "
- "aborting.\n");
- return pos;
- } else {
- pci_read_config_word(pdev, pos + PCI_EXP_DEVCTL, &val16);
- val16 &= ~PCI_EXP_DEVCTL_NOSNOOP_EN;
- val16 |= (PCI_EXP_DEVCTL_CERE |
- PCI_EXP_DEVCTL_NFERE |
- PCI_EXP_DEVCTL_FERE | PCI_EXP_DEVCTL_URRE);
- pci_write_config_word(pdev, pos + PCI_EXP_DEVCTL, val16);
- }
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
--
1.6.0.2
^ permalink raw reply related
* [net-next PATCH 2/8] qlge: Set PCIE max read request size.
From: Ron Mercer @ 2009-10-10 19:35 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer, root
In-Reply-To: <1255203310-18114-1-git-send-email-ron.mercer@qlogic.com>
From: root <root@localhost.localdomain>
Signed-off-by: root <root@localhost.localdomain>
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_main.c | 7 +++++++
1 files changed, 7 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 7a9dca8..aeb0104 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -3881,6 +3881,13 @@ static int __devinit ql_init_device(struct pci_dev *pdev,
qdev->pdev = pdev;
pci_set_drvdata(pdev, ndev);
+ /* Set PCIe read request size */
+ err = pcie_set_readrq(pdev, 4096);
+ if (err) {
+ dev_err(&pdev->dev, "Set readrq failed.\n");
+ goto err_out;
+ }
+
err = pci_request_regions(pdev, DRV_NAME);
if (err) {
dev_err(&pdev->dev, "PCI region request failed.\n");
--
1.6.0.2
^ permalink raw reply related
* [net-next PATCH 3/8] qlge: Add handler for DCBX firmware event.
From: Ron Mercer @ 2009-10-10 19:35 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
In-Reply-To: <1255203310-18114-1-git-send-email-ron.mercer@qlogic.com>
The driver has nothing to do, but this marker prevents the event from
showing up 'not handled'.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_mpi.c | 3 +++
1 files changed, 3 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 99e58e3..2e83c4b 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -446,6 +446,9 @@ static int ql_mpi_handler(struct ql_adapter *qdev, struct mbox_params *mbcp)
ql_aen_lost(qdev, mbcp);
break;
+ case AEN_DCBX_CHG:
+ /* Need to support AEN 8110 */
+ break;
default:
QPRINTK(qdev, DRV, ERR,
"Unsupported AE %.08x.\n", mbcp->mbox_out[0]);
--
1.6.0.2
^ permalink raw reply related
* [net-next PATCH 4/8] qlge: Store firmware revision as early as possible.
From: Ron Mercer @ 2009-10-10 19:35 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
In-Reply-To: <1255203310-18114-1-git-send-email-ron.mercer@qlogic.com>
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_mpi.c | 1 +
1 files changed, 1 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 2e83c4b..9c0dfe0 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -317,6 +317,7 @@ static void ql_init_fw_done(struct ql_adapter *qdev, struct mbox_params *mbcp)
} else {
QPRINTK(qdev, DRV, ERR, "Firmware Revision = 0x%.08x.\n",
mbcp->mbox_out[1]);
+ qdev->fw_rev_id = mbcp->mbox_out[1];
status = ql_cam_route_initialize(qdev);
if (status)
QPRINTK(qdev, IFUP, ERR,
--
1.6.0.2
^ permalink raw reply related
* [net-next PATCH 5/8] qlge: Remove inline math for small rx buf mapping.
From: Ron Mercer @ 2009-10-10 19:35 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
In-Reply-To: <1255203310-18114-1-git-send-email-ron.mercer@qlogic.com>
rx_ring->sbq_buf_len now holds the length of the mapped portion of the
buffer rather than the overall length.
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge.h | 3 ++-
drivers/net/qlge/qlge_main.c | 14 +++++++-------
2 files changed, 9 insertions(+), 8 deletions(-)
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index e7285f0..633fcd1 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -54,7 +54,8 @@
#define RX_RING_SHADOW_SPACE (sizeof(u64) + \
MAX_DB_PAGES_PER_BQ(NUM_SMALL_BUFFERS) * sizeof(u64) + \
MAX_DB_PAGES_PER_BQ(NUM_LARGE_BUFFERS) * sizeof(u64))
-#define SMALL_BUFFER_SIZE 256
+#define SMALL_BUFFER_SIZE 512
+#define SMALL_BUF_MAP_SIZE (SMALL_BUFFER_SIZE / 2)
#define LARGE_BUFFER_SIZE PAGE_SIZE
#define MAX_SPLIT_SIZE 1023
#define QLGE_SB_PAD 32
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index aeb0104..09247ab 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -1147,7 +1147,7 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
sbq_desc->index);
sbq_desc->p.skb =
netdev_alloc_skb(qdev->ndev,
- rx_ring->sbq_buf_size);
+ SMALL_BUFFER_SIZE);
if (sbq_desc->p.skb == NULL) {
QPRINTK(qdev, PROBE, ERR,
"Couldn't get an skb.\n");
@@ -1157,8 +1157,8 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
skb_reserve(sbq_desc->p.skb, QLGE_SB_PAD);
map = pci_map_single(qdev->pdev,
sbq_desc->p.skb->data,
- rx_ring->sbq_buf_size /
- 2, PCI_DMA_FROMDEVICE);
+ rx_ring->sbq_buf_size,
+ PCI_DMA_FROMDEVICE);
if (pci_dma_mapping_error(qdev->pdev, map)) {
QPRINTK(qdev, IFUP, ERR, "PCI mapping failed.\n");
rx_ring->sbq_clean_idx = clean_idx;
@@ -1168,7 +1168,7 @@ static void ql_update_sbq(struct ql_adapter *qdev, struct rx_ring *rx_ring)
}
pci_unmap_addr_set(sbq_desc, mapaddr, map);
pci_unmap_len_set(sbq_desc, maplen,
- rx_ring->sbq_buf_size / 2);
+ rx_ring->sbq_buf_size);
*sbq_desc->addr = cpu_to_le64(map);
}
@@ -2692,7 +2692,7 @@ static int ql_start_rx_ring(struct ql_adapter *qdev, struct rx_ring *rx_ring)
cqicb->sbq_addr =
cpu_to_le64(rx_ring->sbq_base_indirect_dma);
cqicb->sbq_buf_size =
- cpu_to_le16((u16)(rx_ring->sbq_buf_size/2));
+ cpu_to_le16((u16)(rx_ring->sbq_buf_size));
bq_len = (rx_ring->sbq_len == 65536) ? 0 :
(u16) rx_ring->sbq_len;
cqicb->sbq_len = cpu_to_le16(bq_len);
@@ -3268,7 +3268,7 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
ql_write32(qdev, FSC, mask | value);
ql_write32(qdev, SPLT_HDR, SPLT_HDR_EP |
- min(SMALL_BUFFER_SIZE, MAX_SPLIT_SIZE));
+ min(SMALL_BUF_MAP_SIZE, MAX_SPLIT_SIZE));
/* Set RX packet routing to use port/pci function on which the
* packet arrived on in addition to usual frame routing.
@@ -3548,7 +3548,7 @@ static int ql_configure_rings(struct ql_adapter *qdev)
rx_ring->sbq_len = NUM_SMALL_BUFFERS;
rx_ring->sbq_size =
rx_ring->sbq_len * sizeof(__le64);
- rx_ring->sbq_buf_size = SMALL_BUFFER_SIZE * 2;
+ rx_ring->sbq_buf_size = SMALL_BUF_MAP_SIZE;
rx_ring->type = RX_Q;
} else {
/*
--
1.6.0.2
^ permalink raw reply related
* [net-next PATCH 6/8] qlge: Get rid of firmware handler debug code.
From: Ron Mercer @ 2009-10-10 19:35 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
In-Reply-To: <1255203310-18114-1-git-send-email-ron.mercer@qlogic.com>
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_mpi.c | 21 ---------------------
1 files changed, 0 insertions(+), 21 deletions(-)
diff --git a/drivers/net/qlge/qlge_mpi.c b/drivers/net/qlge/qlge_mpi.c
index 9c0dfe0..e497eac 100644
--- a/drivers/net/qlge/qlge_mpi.c
+++ b/drivers/net/qlge/qlge_mpi.c
@@ -1,25 +1,5 @@
#include "qlge.h"
-static void ql_display_mb_sts(struct ql_adapter *qdev,
- struct mbox_params *mbcp)
-{
- int i;
- static char *err_sts[] = {
- "Command Complete",
- "Command Not Supported",
- "Host Interface Error",
- "Checksum Error",
- "Unused Completion Status",
- "Test Failed",
- "Command Parameter Error"};
-
- QPRINTK(qdev, DRV, DEBUG, "%s.\n",
- err_sts[mbcp->mbox_out[0] & 0x0000000f]);
- for (i = 0; i < mbcp->out_count; i++)
- QPRINTK(qdev, DRV, DEBUG, "mbox_out[%d] = 0x%.08x.\n",
- i, mbcp->mbox_out[i]);
-}
-
int ql_read_mpi_reg(struct ql_adapter *qdev, u32 reg, u32 *data)
{
int status;
@@ -540,7 +520,6 @@ static int ql_mailbox_command(struct ql_adapter *qdev, struct mbox_params *mbcp)
MB_CMD_STS_GOOD) &&
((mbcp->mbox_out[0] & 0x0000f000) !=
MB_CMD_STS_INTRMDT)) {
- ql_display_mb_sts(qdev, mbcp);
status = -EIO;
}
end:
--
1.6.0.2
^ permalink raw reply related
* [net-next PATCH 7/8] qlge: Don't fail open when port is not initialized.
From: Ron Mercer @ 2009-10-10 19:35 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
In-Reply-To: <1255203310-18114-1-git-send-email-ron.mercer@qlogic.com>
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge_main.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/qlge/qlge_main.c b/drivers/net/qlge/qlge_main.c
index 09247ab..9eefb11 100644
--- a/drivers/net/qlge/qlge_main.c
+++ b/drivers/net/qlge/qlge_main.c
@@ -3310,10 +3310,8 @@ static int ql_adapter_initialize(struct ql_adapter *qdev)
/* Initialize the port and set the max framesize. */
status = qdev->nic_ops->port_initialize(qdev);
- if (status) {
- QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n");
- return status;
- }
+ if (status)
+ QPRINTK(qdev, IFUP, ERR, "Failed to start port.\n");
/* Set up the MAC address and frame routing filter. */
status = ql_cam_route_initialize(qdev);
--
1.6.0.2
^ permalink raw reply related
* [net-next PATCH 8/8] qlge: Add CBFC pause frame counters to ethtool stats.
From: Ron Mercer @ 2009-10-10 19:35 UTC (permalink / raw)
To: davem; +Cc: netdev, ron.mercer
In-Reply-To: <1255203310-18114-1-git-send-email-ron.mercer@qlogic.com>
Signed-off-by: Ron Mercer <ron.mercer@qlogic.com>
---
drivers/net/qlge/qlge.h | 21 ++++++++++++
drivers/net/qlge/qlge_ethtool.c | 69 +++++++++++++++++++++++++++++++++++++++
2 files changed, 90 insertions(+), 0 deletions(-)
diff --git a/drivers/net/qlge/qlge.h b/drivers/net/qlge/qlge.h
index 633fcd1..fd47691 100644
--- a/drivers/net/qlge/qlge.h
+++ b/drivers/net/qlge/qlge.h
@@ -1363,6 +1363,27 @@ struct nic_stats {
u64 rx_1024_to_1518_pkts;
u64 rx_1519_to_max_pkts;
u64 rx_len_err_pkts;
+ /*
+ * These stats come from offset 500h to 5C8h
+ * in the XGMAC register.
+ */
+ u64 tx_cbfc_pause_frames0;
+ u64 tx_cbfc_pause_frames1;
+ u64 tx_cbfc_pause_frames2;
+ u64 tx_cbfc_pause_frames3;
+ u64 tx_cbfc_pause_frames4;
+ u64 tx_cbfc_pause_frames5;
+ u64 tx_cbfc_pause_frames6;
+ u64 tx_cbfc_pause_frames7;
+ u64 rx_cbfc_pause_frames0;
+ u64 rx_cbfc_pause_frames1;
+ u64 rx_cbfc_pause_frames2;
+ u64 rx_cbfc_pause_frames3;
+ u64 rx_cbfc_pause_frames4;
+ u64 rx_cbfc_pause_frames5;
+ u64 rx_cbfc_pause_frames6;
+ u64 rx_cbfc_pause_frames7;
+ u64 rx_nic_fifo_drop;
};
/*
diff --git a/drivers/net/qlge/qlge_ethtool.c b/drivers/net/qlge/qlge_ethtool.c
index 5207394..aac6c6f 100644
--- a/drivers/net/qlge/qlge_ethtool.c
+++ b/drivers/net/qlge/qlge_ethtool.c
@@ -132,6 +132,41 @@ static void ql_update_stats(struct ql_adapter *qdev)
iter++;
}
+ /*
+ * Get Per-priority TX pause frame counter statistics.
+ */
+ for (i = 0x500; i < 0x540; i += 8) {
+ if (ql_read_xgmac_reg64(qdev, i, &data)) {
+ QPRINTK(qdev, DRV, ERR,
+ "Error reading status register 0x%.04x.\n", i);
+ goto end;
+ } else
+ *iter = data;
+ iter++;
+ }
+
+ /*
+ * Get Per-priority RX pause frame counter statistics.
+ */
+ for (i = 0x568; i < 0x5a8; i += 8) {
+ if (ql_read_xgmac_reg64(qdev, i, &data)) {
+ QPRINTK(qdev, DRV, ERR,
+ "Error reading status register 0x%.04x.\n", i);
+ goto end;
+ } else
+ *iter = data;
+ iter++;
+ }
+
+ /*
+ * Get RX NIC FIFO DROP statistics.
+ */
+ if (ql_read_xgmac_reg64(qdev, 0x5b8, &data)) {
+ QPRINTK(qdev, DRV, ERR,
+ "Error reading status register 0x%.04x.\n", i);
+ goto end;
+ } else
+ *iter = data;
end:
ql_sem_unlock(qdev, qdev->xg_sem_mask);
quit:
@@ -185,6 +220,23 @@ static char ql_stats_str_arr[][ETH_GSTRING_LEN] = {
{"rx_1024_to_1518_pkts"},
{"rx_1519_to_max_pkts"},
{"rx_len_err_pkts"},
+ {"tx_cbfc_pause_frames0"},
+ {"tx_cbfc_pause_frames1"},
+ {"tx_cbfc_pause_frames2"},
+ {"tx_cbfc_pause_frames3"},
+ {"tx_cbfc_pause_frames4"},
+ {"tx_cbfc_pause_frames5"},
+ {"tx_cbfc_pause_frames6"},
+ {"tx_cbfc_pause_frames7"},
+ {"rx_cbfc_pause_frames0"},
+ {"rx_cbfc_pause_frames1"},
+ {"rx_cbfc_pause_frames2"},
+ {"rx_cbfc_pause_frames3"},
+ {"rx_cbfc_pause_frames4"},
+ {"rx_cbfc_pause_frames5"},
+ {"rx_cbfc_pause_frames6"},
+ {"rx_cbfc_pause_frames7"},
+ {"rx_nic_fifo_drop"},
};
static void ql_get_strings(struct net_device *dev, u32 stringset, u8 *buf)
@@ -257,6 +309,23 @@ ql_get_ethtool_stats(struct net_device *ndev,
*data++ = s->rx_1024_to_1518_pkts;
*data++ = s->rx_1519_to_max_pkts;
*data++ = s->rx_len_err_pkts;
+ *data++ = s->tx_cbfc_pause_frames0;
+ *data++ = s->tx_cbfc_pause_frames1;
+ *data++ = s->tx_cbfc_pause_frames2;
+ *data++ = s->tx_cbfc_pause_frames3;
+ *data++ = s->tx_cbfc_pause_frames4;
+ *data++ = s->tx_cbfc_pause_frames5;
+ *data++ = s->tx_cbfc_pause_frames6;
+ *data++ = s->tx_cbfc_pause_frames7;
+ *data++ = s->rx_cbfc_pause_frames0;
+ *data++ = s->rx_cbfc_pause_frames1;
+ *data++ = s->rx_cbfc_pause_frames2;
+ *data++ = s->rx_cbfc_pause_frames3;
+ *data++ = s->rx_cbfc_pause_frames4;
+ *data++ = s->rx_cbfc_pause_frames5;
+ *data++ = s->rx_cbfc_pause_frames6;
+ *data++ = s->rx_cbfc_pause_frames7;
+ *data++ = s->rx_nic_fifo_drop;
}
static int ql_get_settings(struct net_device *ndev,
--
1.6.0.2
^ permalink raw reply related
* [PATCH netnext-2.6] bonding: change bond_create_proc_entry() to return void
From: Nicolas de Pesloüan @ 2009-10-10 20:41 UTC (permalink / raw)
To: fubar, davem, netdev, bonding-devel, rakib.mullick
Cc: Nicolas de Pesloüan
In-Reply-To: <b9df5fa10910091910u1b6bf14bg2781cb12c58b21f9@mail.gmail.com>
The function bond_create_proc_entry is currently of type int.
Two versions of this function exist:
The one in the ifdef CONFIG_PROC_FS branch always return 0.
The one in the else branch (which is empty) return nothing.
When CONFIG_PROC_FS is undef, this cause the following warning:
drivers/net/bonding/bond_main.c: In function `bond_create_proc_entry':
drivers/net/bonding/bond_main.c:3393: warning: control reaches end of
non-void function
No caller of this function use the returned value.
So change the returned type from int to void and remove the
useless return 0; .
Signed-off-by: Nicolas de Pesloüan <nicolas.2p.debian@free.fr>
Reported-by: Rakib Mullick <rakib.mullick@gmail.com>
---
drivers/net/bonding/bond_main.c | 6 ++----
1 files changed, 2 insertions(+), 4 deletions(-)
diff --git a/drivers/net/bonding/bond_main.c b/drivers/net/bonding/bond_main.c
index ef6af1c..feb03ad 100644
--- a/drivers/net/bonding/bond_main.c
+++ b/drivers/net/bonding/bond_main.c
@@ -3375,7 +3375,7 @@ static const struct file_operations bond_info_fops = {
.release = seq_release,
};
-static int bond_create_proc_entry(struct bonding *bond)
+static void bond_create_proc_entry(struct bonding *bond)
{
struct net_device *bond_dev = bond->dev;
@@ -3390,8 +3390,6 @@ static int bond_create_proc_entry(struct bonding *bond)
else
memcpy(bond->proc_file_name, bond_dev->name, IFNAMSIZ);
}
-
- return 0;
}
static void bond_remove_proc_entry(struct bonding *bond)
@@ -3430,7 +3428,7 @@ static void bond_destroy_proc_dir(void)
#else /* !CONFIG_PROC_FS */
-static int bond_create_proc_entry(struct bonding *bond)
+static void bond_create_proc_entry(struct bonding *bond)
{
}
--
1.6.3.3
^ permalink raw reply related
* Re: PATCH: Network Device Naming mechanism and policy
From: Greg KH @ 2009-10-10 21:06 UTC (permalink / raw)
To: Stephen Hemminger
Cc: Matt Domsch, netdev, linux-hotplug, Narendra_K, jordan_hargrave
In-Reply-To: <20091010113219.3136fb8b@s6510>
On Sat, Oct 10, 2009 at 11:32:19AM -0700, Stephen Hemminger wrote:
>
> BTW, for our distro, we are looking into device renaming based on PCI slot
> because that is what router OS's do. Customers expect if they replace the card
> in slot 0, it will come back with the same name. This is not what server
> customers expect.
If your bios exposes the PCI slots to userspace (through the proper ACPI
namespace), doing this type of naming should be trivial with some simple
udev rules, no additional kernel infrastructure is needed.
thanks,
greg k-h
^ permalink raw reply
* Re: [PATCH 00/31] Swap over NFS -v20
From: Pavel Machek @ 2009-10-10 21:10 UTC (permalink / raw)
To: Peter Zijlstra
Cc: Christoph Hellwig, Suresh Jayaraman, Linus Torvalds,
Andrew Morton, linux-kernel, linux-mm, netdev, Neil Brown,
Miklos Szeredi, Wouter Verhelst, trond.myklebust
In-Reply-To: <1255177421.11081.0.camel@twins>
On Sat 2009-10-10 14:23:41, Peter Zijlstra wrote:
> On Sat, 2009-10-10 at 14:06 +0200, Pavel Machek wrote:
> > Hi!
> >
> > > > One of them
> > > > would be the whole VM/net work to just make swap over nbd/iscsi safe.
> > >
> > > Getting those two 'fixed' is going to be tons of interesting work
> > > because they involve interaction with userspace daemons.
> > >
> > > NBD has fairly simple userspace, but iSCSI has a rather large userspace
> > > footprint and a rather complicated user/kernel interaction which will be
> > > mighty interesting to get allocation safe.
> > >
> > > Ideally the swap-over-$foo bits have no userspace component.
> > >
> > > That said, Wouter is the NBD userspace maintainer and has expressed
> > > interest into looking at making that work, but its sure going to be
> > > non-trivial, esp. since exposing PF_MEMALLOC to userspace is a, not over
> > > my dead-bodym like thing.
> >
> > Well, as long as nbd-server is on separate machine (with real swap),
> > safe swapping over network should be ok, without PF_MEMALLOC for
> > userspace or similar nightmares, right?
>
> Nope, as soon as the nbd-client looses its connection you're up shit
> creek.
Oops, right. Putting reconnect logic into the kernel would make sense.
I misunderstood your proposal. I thought you'd want to put
nbd-_server_ into the kernel too. I guess we violently agree that
that's unneccessary.
Pavel
--
(english) http://www.livejournal.com/~pavelmachek
(cesky, pictures) http://atrey.karlin.mff.cuni.cz/~pavel/picture/horses/blog.html
--
To unsubscribe, send a message with 'unsubscribe linux-mm' in
the body to majordomo@kvack.org. For more info on Linux MM,
see: http://www.linux-mm.org/ .
Don't email: <a href=mailto:"dont@kvack.org"> email@kvack.org </a>
^ permalink raw reply
* Re: PATCH: Network Device Naming mechanism and policy
From: Greg KH @ 2009-10-10 21:10 UTC (permalink / raw)
To: Ben Hutchings
Cc: Sujit K M, Matt Domsch, Stephen Hemminger, netdev, linux-hotplug,
Narendra_K, jordan_hargrave
In-Reply-To: <1255201230.25061.60.camel@localhost>
On Sat, Oct 10, 2009 at 08:00:30PM +0100, Ben Hutchings wrote:
> On the other hand, the netlink configuration APIs already use ifindex so
> it may be better just to say that the device ioctls are deprecated and
> applications should use netlink.
I thought that is what was already encouraged to happen.
> > > > That is why all distros name network devices based on the only
> > > > deterministic thing they have today, the MAC address. ?I still fail to
> > > > see why you do not like this solution, it is honestly the only way to
> > > > properly name network devices in a sane manner.
> > >
> > > This is feature that needs to be implemented. As per the rules followed.
> >
> > This feature is already implemented today, all distros have it.
>
> No, see below.
Yes, if not, file a bug in your distro, all of the infrastructure is
already in place, and the udev rules and scripts are already written.
> > > > All distros also provide a way to easily rename the network devices, to
> > > > place a specific name on a specific MAC address, so again, this should
> > > > all be solved already.
> > > >
> > > > No matter how badly your BIOS teams mess up the PCI enumeration order :)
> > >
> > > This is an problem, But I think this can be solved by implementing some of the
> > > routines in the network device.
> >
> > I don't, see the rules that your distro ships today for persistant
> > network devices, it's already there, no need to change the kernel at
> > all.
>
> The udev persistent net rules work tolerably well for a single system
> with a stable set of net devices.
>
> They do not solve the problem Matt's talking about, which is lack of
> consistency between multiple systems, because the initial enumeration
> order is not predictable.
Again, you name the device as a MAC address. Or something else that the
BIOS exports in a unique manner (PCI slot name, etc.). That is
consistant. If not, then fix the BIOS.
> They also result in name changes when a NIC (or motherboard) is swapped.
> For some users, that's fine; for others, it's not.
>
> The ability to specify NICs by port name or PCI address should solve
> these problems.
That can be done today quite easily. But note that PCI addresses are
not guaranteed to be stable. As lots of machines are known to have
happen.
Again, none of this requires any kernel changes today at all, let alone
adding dummy char devices for network devices.
thanks,
greg k-h
^ permalink raw reply
* Re: PATCH: Network Device Naming mechanism and policy
From: Greg KH @ 2009-10-10 21:13 UTC (permalink / raw)
To: Bryan Kadzban
Cc: Matt Domsch, Stephen Hemminger, netdev, linux-hotplug, Narendra_K,
jordan_hargrave
In-Reply-To: <4AD0C598.4070403@kadzban.is-a-geek.net>
On Sat, Oct 10, 2009 at 10:34:16AM -0700, Bryan Kadzban wrote:
> Greg KH wrote:
> > On Sat, Oct 10, 2009 at 07:47:32AM -0500, Matt Domsch wrote:
> >> On Fri, Oct 09, 2009 at 10:23:08PM -0700, Greg KH wrote:
> >>> On Fri, Oct 09, 2009 at 11:40:57PM -0500, Matt Domsch wrote:
> >>>> The fundamental roadblock to this is that enumeration !=
> >>>> naming, except that it is for network devices, and we keep
> >>>> changing the enumeration order.
> >>> No, the hardware changes the enumeration order, it places _no_
> >>> guarantees on what order stuff will be found in. So this is not
> >>> the kernel changing, just to be clear.
> >> Over time the kernel has changed its enumeration mechanisms, and
> >> introduced parallelism into the process (which is a good thing),
> >> which, from a user perspective, makes names nondeterministic. Yes,
> >> fixing this up by hard-coding MAC addresses after install has been
> >> the traditional mechanism to address this. I think there's a
> >> better way.
> >
> > Ok, but that way can be done in userspace, without the need for this
> > char device, right?
>
> For the record -- when I tried to send a patch that did exactly this
> (provided an option to use by-path persistence for network drivers), it
> was rejected because "that doesn't work for USB".
>
> True, it doesn't. But by-mac (what we have today) doesn't work for
> replacing motherboards in a random home system (that can't override the
> MAC address in the BIOS), either.
If you replace a motherboard, you honestly expect no configuration to be
needed to be changed? If so, then don't use the MAC naming scheme for
your systems.
> > But this code is not a requirement to "solve" the fact that network
> > devices can show up in different order, that problem can be solved as
> > long as the user picks a single way to name the devices, using tools
> > that are already present today in distros.
>
> This code is not a requirement, no. But -- as you say -- it does
> provide a halfway-decent way to assign multiple names to a NIC. And
> that provides admins the choice to use a couple different persistence
> schemes, depending on how they expect their hardware to work.
But the names need to then be resolved back to a "real" kernel name in
order to do anything with that network connection, as the char devices
are not real ones. So that adds an additional layer of complexity on
all of the system configuration tools.
thanks,
greg k-h
^ permalink raw reply
* [PATCH] ax25: unsigned cannot be less than 0 in ax25_ctl_ioctl()
From: Roel Kluin @ 2009-10-10 21:22 UTC (permalink / raw)
To: Joerg Reuter, linux-hams, Andrew Morton, netdev
struct ax25_ctl_struct member `arg' is unsigned and cannot be less
than 0.
Signed-off-by: Roel Kluin <roel.kluin@gmail.com>
---
If the ax25_ctl.arg limit is known to be lower, please suggest
other values.
diff --git a/net/ax25/af_ax25.c b/net/ax25/af_ax25.c
index f454607..0d99704 100644
--- a/net/ax25/af_ax25.c
+++ b/net/ax25/af_ax25.c
@@ -398,14 +398,14 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
break;
case AX25_T1:
- if (ax25_ctl.arg < 1)
+ if (ax25_ctl.arg < 1 || ax25_ctl.arg * HZ > ULONG_MAX)
goto einval_put;
ax25->rtt = (ax25_ctl.arg * HZ) / 2;
ax25->t1 = ax25_ctl.arg * HZ;
break;
case AX25_T2:
- if (ax25_ctl.arg < 1)
+ if (ax25_ctl.arg < 1 || ax25_ctl.arg * HZ > ULONG_MAX)
goto einval_put;
ax25->t2 = ax25_ctl.arg * HZ;
break;
@@ -418,13 +418,13 @@ static int ax25_ctl_ioctl(const unsigned int cmd, void __user *arg)
break;
case AX25_T3:
- if (ax25_ctl.arg < 0)
+ if (ax25_ctl.arg * HZ > ULONG_MAX)
goto einval_put;
ax25->t3 = ax25_ctl.arg * HZ;
break;
case AX25_IDLE:
- if (ax25_ctl.arg < 0)
+ if (ax25_ctl.arg * 60 * HZ > ULONG_MAX)
goto einval_put;
ax25->idle = ax25_ctl.arg * 60 * HZ;
break;
^ permalink raw reply related
* Re: Very strange issues with ethernet wake on lan
From: Maxim Levitsky @ 2009-10-10 21:37 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: netdev@vger.kernel.org, linux-pm@lists.linux-foundation.org
In-Reply-To: <200909292228.18200.rjw@sisk.pl>
On Tue, 2009-09-29 at 22:28 +0200, Rafael J. Wysocki wrote:
> On Sunday 16 August 2009, Maxim Levitsky wrote:
> > Hi,
> >
> > I have recently put back the davicom dm9009 ethernet card into my
> > computer.
> >
> > Some long time ago, I have written its suspend/resume routines.
> > Now I see that few things have changed, like I need to enable wake in
> > sysfs or better patch the code to do so, some nice helpers like
> > pci_prepare_to_sleep have arrived, etc.
> >
> >
> > I narrowed the strange issue down to following situation:
> >
> > I reload dmfe.ko (and networkmanager is disabled)
> > I don't ifup the device, thus pretty much no hardware initialization
> > takes place (but this appears not to matter anyway)
> >
> > I then suspend the system, and WOL doesn't work (I have patched the
> > driver to enable WOL automaticly)
> >
> > I then, suspend again. WOL works, and continues to work as long as I
> > don't reload the driver. If I do, same situation repeats.
> >
> > Also, after a boot, WOL works, so a reload cycle triggers that issue.
> >
> > And most importantly, if I don't do a
> >
> > pci_set_power_state(pci_dev, pci_choose_state (pci_dev, state));
> >
> > in .suspend, then WOL always works.
> >
> > and I have even tried to set state manually to PCI_D3hot or PCI_D3cold,
> >
> > I also tried to use pci_save_state
> >
> >
> > I also have 2 copies of this card, and both have this issue.
> > I also tried 2 pci slots.
> >
> > Kernel is vanilla 2.6.31-rc5
>
> Please check if this still happens with 2.6.32-rc1.
It doesn't! (-git as of today tested)
Thanks,
Best regards,
Maxim Levitsky
>
> Best,
> Rafael
> --
> To unsubscribe from this list: send the line "unsubscribe netdev" in
> the body of a message to majordomo@vger.kernel.org
> More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Real networking namespace
From: Paul Moore @ 2009-10-10 21:40 UTC (permalink / raw)
To: shemminger; +Cc: sds, linux-security-module, viro, netdev, jmorris
In-Reply-To: <20091009190820.0a0f09c2@nehalam>
------- Original message -------
> From: Stephen Hemminger <shemminger@linux-foundation.org>
> Cc: sds@tycho.nsa.gov, linux-security-module@vger.kernel.org,
> viro@zeniv.linux.org.uk, netdev@vger.kernel.org, jmorris@namei.org
> Sent: 10/9, 22:08
>
> On Fri, 9 Oct 2009 18:12:15 -0400
> Paul Moore <paul.moore@hp.com> wrote:
>
>> On Friday 09 October 2009 12:44:52 pm Stephen Smalley wrote:
>> > On Fri, 2009-10-09 at 12:37 -0400, Stephen Smalley wrote:
>> > > On Fri, 2009-10-09 at 08:38 -0700, Stephen Hemminger wrote:
>> > > > The existing networking namespace model is unattractive for what I
>> > > > want, has anyone investigated better alternatives?
>> > > >
>> > > > I would like to be able to allow access to a network interface and
>> > > > associated objects (routing tables etc), to be controlled by
>> Mandatory
>> > > > Access Control API's. I.e grant access to eth0 and to only certain
>> > > > processes. Some the issues with the existing models are:
>> > > > * eth0 and associated objects don't really exist in filesystem
>> so
>> > > > not subject to LSM style control (SeLinux/SMACK/TOMOYO)
>>
>> As Stephen points out, SELinux does have the ability to assign security
>> labels
>> to network interfaces, check out the 'semanage' command. A while back I
>> wrote
>> up something about the SELinux network "ingress/egress" access controls:
>>
>> * http://paulmoore.livejournal.com/2128.html
>
> I was hoping to be able to not have inaccessible interfaces visible,
> is it possible to not have interfaces show up in commands like:
> ip link show
> or sysfs?
I haven't looked at the code for 'ip' but I'm pretty sure it uses netlink
to configure the kernel, yes? If that is the case, no I don't believe any
of the current LSMs provide that level of granularity (netlink, generic
netlink in particular, is a bit of a problem spot at the moment). As for
sysfs, I don't believe we label the interface related files based on their
semanage labels but I could be wrong - we've got plenty of good people
already working on fs labeling so I spend most of my time worrying about
network labeling.
--
paul moore
linux @ hp
^ permalink raw reply
* Re: Very strange issues with ethernet wake on lan
From: Rafael J. Wysocki @ 2009-10-10 21:45 UTC (permalink / raw)
To: Maxim Levitsky
Cc: netdev@vger.kernel.org, linux-pm@lists.linux-foundation.org
In-Reply-To: <1255210639.4199.0.camel@maxim-laptop>
On Saturday 10 October 2009, Maxim Levitsky wrote:
> On Tue, 2009-09-29 at 22:28 +0200, Rafael J. Wysocki wrote:
> > On Sunday 16 August 2009, Maxim Levitsky wrote:
> > > Hi,
> > >
> > > I have recently put back the davicom dm9009 ethernet card into my
> > > computer.
> > >
> > > Some long time ago, I have written its suspend/resume routines.
> > > Now I see that few things have changed, like I need to enable wake in
> > > sysfs or better patch the code to do so, some nice helpers like
> > > pci_prepare_to_sleep have arrived, etc.
> > >
> > >
> > > I narrowed the strange issue down to following situation:
> > >
> > > I reload dmfe.ko (and networkmanager is disabled)
> > > I don't ifup the device, thus pretty much no hardware initialization
> > > takes place (but this appears not to matter anyway)
> > >
> > > I then suspend the system, and WOL doesn't work (I have patched the
> > > driver to enable WOL automaticly)
> > >
> > > I then, suspend again. WOL works, and continues to work as long as I
> > > don't reload the driver. If I do, same situation repeats.
> > >
> > > Also, after a boot, WOL works, so a reload cycle triggers that issue.
> > >
> > > And most importantly, if I don't do a
> > >
> > > pci_set_power_state(pci_dev, pci_choose_state (pci_dev, state));
> > >
> > > in .suspend, then WOL always works.
> > >
> > > and I have even tried to set state manually to PCI_D3hot or PCI_D3cold,
> > >
> > > I also tried to use pci_save_state
> > >
> > >
> > > I also have 2 copies of this card, and both have this issue.
> > > I also tried 2 pci slots.
> > >
> > > Kernel is vanilla 2.6.31-rc5
> >
> > Please check if this still happens with 2.6.32-rc1.
>
> It doesn't! (-git as of today tested)
Great, thanks for verifying.
Best,
Rafael
^ permalink raw reply
* [PATCH 1/7] bnx2x: Refactor bnx2x_sp_post().
From: Michael Chan @ 2009-10-10 23:46 UTC (permalink / raw)
To: davem; +Cc: netdev, michaelc, shmulikr, eilong, Michael Chan
Some of the SPQ (slow-path queue) operations will be used
by the cnic code in later patches.
Signed-off-by: Shmulik Ravid - Rabinovitz <shmulikr@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Acked-by: Eilon Greenstein <eilong@broadcom.com>
---
drivers/net/bnx2x_main.c | 62 ++++++++++++++++++++++++++++-----------------
1 files changed, 38 insertions(+), 24 deletions(-)
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index c0abfc4..713d669 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -2638,11 +2638,40 @@ static void bnx2x_dcc_event(struct bnx2x *bp, u32 dcc_event)
bnx2x_fw_command(bp, DRV_MSG_CODE_DCC_OK);
}
+/* must be called under the spq lock */
+static inline struct eth_spe *bnx2x_sp_get_next(struct bnx2x *bp)
+{
+ struct eth_spe *next_spe = bp->spq_prod_bd;
+
+ if (bp->spq_prod_bd == bp->spq_last_bd) {
+ bp->spq_prod_bd = bp->spq;
+ bp->spq_prod_idx = 0;
+ DP(NETIF_MSG_TIMER, "end of spq\n");
+ } else {
+ bp->spq_prod_bd++;
+ bp->spq_prod_idx++;
+ }
+ return next_spe;
+}
+
+/* must be called under the spq lock */
+static inline void bnx2x_sp_prod_update(struct bnx2x *bp)
+{
+ int func = BP_FUNC(bp);
+
+ /* Make sure that BD data is updated before writing the producer */
+ wmb();
+
+ REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
+ bp->spq_prod_idx);
+ mmiowb();
+}
+
/* the slow path queue is odd since completions arrive on the fastpath ring */
static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
u32 data_hi, u32 data_lo, int common)
{
- int func = BP_FUNC(bp);
+ struct eth_spe *spe;
DP(BNX2X_MSG_SP/*NETIF_MSG_TIMER*/,
"SPQE (%x:%x) command %d hw_cid %x data (%x:%x) left %x\n",
@@ -2664,38 +2693,23 @@ static int bnx2x_sp_post(struct bnx2x *bp, int command, int cid,
return -EBUSY;
}
+ spe = bnx2x_sp_get_next(bp);
+
/* CID needs port number to be encoded int it */
- bp->spq_prod_bd->hdr.conn_and_cmd_data =
+ spe->hdr.conn_and_cmd_data =
cpu_to_le32(((command << SPE_HDR_CMD_ID_SHIFT) |
HW_CID(bp, cid)));
- bp->spq_prod_bd->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
+ spe->hdr.type = cpu_to_le16(ETH_CONNECTION_TYPE);
if (common)
- bp->spq_prod_bd->hdr.type |=
+ spe->hdr.type |=
cpu_to_le16((1 << SPE_HDR_COMMON_RAMROD_SHIFT));
- bp->spq_prod_bd->data.mac_config_addr.hi = cpu_to_le32(data_hi);
- bp->spq_prod_bd->data.mac_config_addr.lo = cpu_to_le32(data_lo);
+ spe->data.mac_config_addr.hi = cpu_to_le32(data_hi);
+ spe->data.mac_config_addr.lo = cpu_to_le32(data_lo);
bp->spq_left--;
- if (bp->spq_prod_bd == bp->spq_last_bd) {
- bp->spq_prod_bd = bp->spq;
- bp->spq_prod_idx = 0;
- DP(NETIF_MSG_TIMER, "end of spq\n");
-
- } else {
- bp->spq_prod_bd++;
- bp->spq_prod_idx++;
- }
-
- /* Make sure that BD data is updated before writing the producer */
- wmb();
-
- REG_WR(bp, BAR_XSTRORM_INTMEM + XSTORM_SPQ_PROD_OFFSET(func),
- bp->spq_prod_idx);
-
- mmiowb();
-
+ bnx2x_sp_prod_update(bp);
spin_unlock_bh(&bp->spq_lock);
return 0;
}
--
1.6.4.GIT
^ permalink raw reply related
* [PATCH 2/7] bnx2x: Refactor MAC address setup code.
From: Michael Chan @ 2009-10-10 23:46 UTC (permalink / raw)
To: davem; +Cc: netdev, michaelc, shmulikr, eilong, Michael Chan
In-Reply-To: <1255218419-17320-1-git-send-email-mchan@broadcom.com>
For iSCSI MAC address setup in later patches.
Signed-off-by: Shmulik Ravid - Rabinovitz <shmulikr@broadcom.com>
Signed-off-by: Michael Chan <mchan@broadcom.com>
Acked-by: Eilon Greenstein <eilong@broadcom.com>
---
drivers/net/bnx2x.h | 4 +-
drivers/net/bnx2x_main.c | 162 ++++++++++++++++++++++++++++++++--------------
2 files changed, 114 insertions(+), 52 deletions(-)
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index bbf8422..1f07063 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -863,8 +863,8 @@ struct bnx2x {
/* Flags for marking that there is a STAT_QUERY or
SET_MAC ramrod pending */
- u8 stats_pending;
- u8 set_mac_pending;
+ int stats_pending;
+ int set_mac_pending;
/* End of fields used in the performance code paths */
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 713d669..02ce3b3 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -1026,12 +1026,15 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN):
case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DIAG):
DP(NETIF_MSG_IFUP, "got set mac ramrod\n");
- bp->set_mac_pending = 0;
+ bp->set_mac_pending--;
+ smp_wmb();
break;
case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_CLOSING_WAIT4_HALT):
case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DISABLED):
DP(NETIF_MSG_IFDOWN, "got (un)set mac ramrod\n");
+ bp->set_mac_pending--;
+ smp_wmb();
break;
default:
@@ -2530,7 +2533,7 @@ u32 bnx2x_fw_command(struct bnx2x *bp, u32 command)
}
static void bnx2x_set_storm_rx_mode(struct bnx2x *bp);
-static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set);
+static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set);
static void bnx2x_set_rx_mode(struct net_device *dev);
static void bnx2x_e1h_disable(struct bnx2x *bp)
@@ -2546,7 +2549,7 @@ static void bnx2x_e1h_disable(struct bnx2x *bp)
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
- bnx2x_set_mac_addr_e1h(bp, 0);
+ bnx2x_set_eth_mac_addr_e1h(bp, 0);
for (i = 0; i < MC_HASH_SIZE; i++)
REG_WR(bp, MC_HASH_OFFSET(bp, i), 0);
@@ -2560,7 +2563,7 @@ static void bnx2x_e1h_enable(struct bnx2x *bp)
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 1);
- bnx2x_set_mac_addr_e1h(bp, 1);
+ bnx2x_set_eth_mac_addr_e1h(bp, 1);
/* Tx queue should be only reenabled */
netif_tx_wake_all_queues(bp->dev);
@@ -7036,7 +7039,19 @@ static void bnx2x_netif_stop(struct bnx2x *bp, int disable_hw)
* Init service functions
*/
-static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set)
+/**
+ * Sets a MAC in a CAM for a few L2 Clients for E1 chip
+ *
+ * @param bp driver descriptor
+ * @param set set or clear an entry (1 or 0)
+ * @param mac pointer to a buffer containing a MAC
+ * @param cl_bit_vec bit vector of clients to register a MAC for
+ * @param cam_offset offset in a CAM to use
+ * @param with_bcast set broadcast MAC as well
+ */
+static void bnx2x_set_mac_addr_e1_gen(struct bnx2x *bp, int set, u8 *mac,
+ u32 cl_bit_vec, u8 cam_offset,
+ u8 with_bcast)
{
struct mac_configuration_cmd *config = bnx2x_sp(bp, mac_config);
int port = BP_PORT(bp);
@@ -7045,25 +7060,25 @@ static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set)
* unicasts 0-31:port0 32-63:port1
* multicast 64-127:port0 128-191:port1
*/
- config->hdr.length = 2;
- config->hdr.offset = port ? 32 : 0;
- config->hdr.client_id = bp->fp->cl_id;
+ config->hdr.length = 1 + (with_bcast ? 1 : 0);
+ config->hdr.offset = cam_offset;
+ config->hdr.client_id = 0xff;
config->hdr.reserved1 = 0;
/* primary MAC */
config->config_table[0].cam_entry.msb_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[0]);
+ swab16(*(u16 *)&mac[0]);
config->config_table[0].cam_entry.middle_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[2]);
+ swab16(*(u16 *)&mac[2]);
config->config_table[0].cam_entry.lsb_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[4]);
+ swab16(*(u16 *)&mac[4]);
config->config_table[0].cam_entry.flags = cpu_to_le16(port);
if (set)
config->config_table[0].target_table_entry.flags = 0;
else
CAM_INVALIDATE(config->config_table[0]);
config->config_table[0].target_table_entry.clients_bit_vector =
- cpu_to_le32(1 << BP_L_ID(bp));
+ cpu_to_le32(cl_bit_vec);
config->config_table[0].target_table_entry.vlan_id = 0;
DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x)\n",
@@ -7073,47 +7088,58 @@ static void bnx2x_set_mac_addr_e1(struct bnx2x *bp, int set)
config->config_table[0].cam_entry.lsb_mac_addr);
/* broadcast */
- config->config_table[1].cam_entry.msb_mac_addr = cpu_to_le16(0xffff);
- config->config_table[1].cam_entry.middle_mac_addr = cpu_to_le16(0xffff);
- config->config_table[1].cam_entry.lsb_mac_addr = cpu_to_le16(0xffff);
- config->config_table[1].cam_entry.flags = cpu_to_le16(port);
- if (set)
- config->config_table[1].target_table_entry.flags =
- TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST;
- else
- CAM_INVALIDATE(config->config_table[1]);
- config->config_table[1].target_table_entry.clients_bit_vector =
- cpu_to_le32(1 << BP_L_ID(bp));
- config->config_table[1].target_table_entry.vlan_id = 0;
+ if (with_bcast) {
+ config->config_table[1].cam_entry.msb_mac_addr =
+ cpu_to_le16(0xffff);
+ config->config_table[1].cam_entry.middle_mac_addr =
+ cpu_to_le16(0xffff);
+ config->config_table[1].cam_entry.lsb_mac_addr =
+ cpu_to_le16(0xffff);
+ config->config_table[1].cam_entry.flags = cpu_to_le16(port);
+ if (set)
+ config->config_table[1].target_table_entry.flags =
+ TSTORM_CAM_TARGET_TABLE_ENTRY_BROADCAST;
+ else
+ CAM_INVALIDATE(config->config_table[1]);
+ config->config_table[1].target_table_entry.clients_bit_vector =
+ cpu_to_le32(cl_bit_vec);
+ config->config_table[1].target_table_entry.vlan_id = 0;
+ }
bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
U64_HI(bnx2x_sp_mapping(bp, mac_config)),
U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
}
-static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set)
+/**
+ * Sets a MAC in a CAM for a few L2 Clients for E1H chip
+ *
+ * @param bp driver descriptor
+ * @param set set or clear an entry (1 or 0)
+ * @param mac pointer to a buffer containing a MAC
+ * @param cl_bit_vec bit vector of clients to register a MAC for
+ * @param cam_offset offset in a CAM to use
+ */
+static void bnx2x_set_mac_addr_e1h_gen(struct bnx2x *bp, int set, u8 *mac,
+ u32 cl_bit_vec, u8 cam_offset)
{
struct mac_configuration_cmd_e1h *config =
(struct mac_configuration_cmd_e1h *)bnx2x_sp(bp, mac_config);
- /* CAM allocation for E1H
- * unicasts: by func number
- * multicast: 20+FUNC*20, 20 each
- */
config->hdr.length = 1;
- config->hdr.offset = BP_FUNC(bp);
- config->hdr.client_id = bp->fp->cl_id;
+ config->hdr.offset = cam_offset;
+ config->hdr.client_id = 0xff;
config->hdr.reserved1 = 0;
/* primary MAC */
config->config_table[0].msb_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[0]);
+ swab16(*(u16 *)&mac[0]);
config->config_table[0].middle_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[2]);
+ swab16(*(u16 *)&mac[2]);
config->config_table[0].lsb_mac_addr =
- swab16(*(u16 *)&bp->dev->dev_addr[4]);
+ swab16(*(u16 *)&mac[4]);
config->config_table[0].clients_bit_vector =
- cpu_to_le32(1 << BP_L_ID(bp));
+ cpu_to_le32(cl_bit_vec);
config->config_table[0].vlan_id = 0;
config->config_table[0].e1hov_id = cpu_to_le16(bp->e1hov);
if (set)
@@ -7122,11 +7148,11 @@ static void bnx2x_set_mac_addr_e1h(struct bnx2x *bp, int set)
config->config_table[0].flags =
MAC_CONFIGURATION_ENTRY_E1H_ACTION_TYPE;
- DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x) E1HOV %d CLID %d\n",
+ DP(NETIF_MSG_IFUP, "%s MAC (%04x:%04x:%04x) E1HOV %d CLID mask %d\n",
(set ? "setting" : "clearing"),
config->config_table[0].msb_mac_addr,
config->config_table[0].middle_mac_addr,
- config->config_table[0].lsb_mac_addr, bp->e1hov, BP_L_ID(bp));
+ config->config_table[0].lsb_mac_addr, bp->e1hov, cl_bit_vec);
bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
U64_HI(bnx2x_sp_mapping(bp, mac_config)),
@@ -7178,6 +7204,31 @@ static int bnx2x_wait_ramrod(struct bnx2x *bp, int state, int idx,
return -EBUSY;
}
+static void bnx2x_set_eth_mac_addr_e1h(struct bnx2x *bp, int set)
+{
+ bp->set_mac_pending++;
+ smp_wmb();
+
+ bnx2x_set_mac_addr_e1h_gen(bp, set, bp->dev->dev_addr,
+ (1 << bp->fp->cl_id), BP_FUNC(bp));
+
+ /* Wait for a completion */
+ bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+}
+
+static void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
+{
+ bp->set_mac_pending++;
+ smp_wmb();
+
+ bnx2x_set_mac_addr_e1_gen(bp, set, bp->dev->dev_addr,
+ (1 << bp->fp->cl_id), (BP_PORT(bp) ? 32 : 0),
+ 1);
+
+ /* Wait for a completion */
+ bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+}
+
static int bnx2x_setup_leading(struct bnx2x *bp)
{
int rc;
@@ -7452,9 +7503,9 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
if (CHIP_IS_E1(bp))
- bnx2x_set_mac_addr_e1(bp, 1);
+ bnx2x_set_eth_mac_addr_e1(bp, 1);
else
- bnx2x_set_mac_addr_e1h(bp, 1);
+ bnx2x_set_eth_mac_addr_e1h(bp, 1);
}
if (bp->port.pmf)
@@ -7717,7 +7768,7 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
struct mac_configuration_cmd *config =
bnx2x_sp(bp, mcast_config);
- bnx2x_set_mac_addr_e1(bp, 0);
+ bnx2x_set_eth_mac_addr_e1(bp, 0);
for (i = 0; i < config->hdr.length; i++)
CAM_INVALIDATE(config->config_table[i]);
@@ -7730,6 +7781,9 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
config->hdr.client_id = bp->fp->cl_id;
config->hdr.reserved1 = 0;
+ bp->set_mac_pending++;
+ smp_wmb();
+
bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
U64_LO(bnx2x_sp_mapping(bp, mcast_config)), 0);
@@ -7737,7 +7791,7 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
} else { /* E1H */
REG_WR(bp, NIG_REG_LLH0_FUNC_EN + port*8, 0);
- bnx2x_set_mac_addr_e1h(bp, 0);
+ bnx2x_set_eth_mac_addr_e1h(bp, 0);
for (i = 0; i < MC_HASH_SIZE; i++)
REG_WR(bp, MC_HASH_OFFSET(bp, i), 0);
@@ -8520,6 +8574,14 @@ static void __devinit bnx2x_link_settings_requested(struct bnx2x *bp)
bp->link_params.req_flow_ctrl, bp->port.advertising);
}
+static void __devinit bnx2x_set_mac_buf(u8 *mac_buf, u32 mac_lo, u16 mac_hi)
+{
+ mac_hi = cpu_to_be16(mac_hi);
+ mac_lo = cpu_to_be32(mac_lo);
+ memcpy(mac_buf, &mac_hi, sizeof(mac_hi));
+ memcpy(mac_buf + sizeof(mac_hi), &mac_lo, sizeof(mac_lo));
+}
+
static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
{
int port = BP_PORT(bp);
@@ -8601,12 +8663,7 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_upper);
val = SHMEM_RD(bp, dev_info.port_hw_config[port].mac_lower);
- bp->dev->dev_addr[0] = (u8)(val2 >> 8 & 0xff);
- bp->dev->dev_addr[1] = (u8)(val2 & 0xff);
- bp->dev->dev_addr[2] = (u8)(val >> 24 & 0xff);
- bp->dev->dev_addr[3] = (u8)(val >> 16 & 0xff);
- bp->dev->dev_addr[4] = (u8)(val >> 8 & 0xff);
- bp->dev->dev_addr[5] = (u8)(val & 0xff);
+ bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2);
memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
}
@@ -10232,14 +10289,16 @@ static int bnx2x_test_intr(struct bnx2x *bp)
config->hdr.client_id = bp->fp->cl_id;
config->hdr.reserved1 = 0;
+ bp->set_mac_pending++;
+ smp_wmb();
rc = bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
U64_HI(bnx2x_sp_mapping(bp, mac_config)),
U64_LO(bnx2x_sp_mapping(bp, mac_config)), 0);
if (rc == 0) {
- bp->set_mac_pending++;
for (i = 0; i < 10; i++) {
if (!bp->set_mac_pending)
break;
+ smp_rmb();
msleep_interruptible(10);
}
if (i == 10)
@@ -11337,6 +11396,9 @@ static void bnx2x_set_rx_mode(struct net_device *dev)
config->hdr.client_id = bp->fp->cl_id;
config->hdr.reserved1 = 0;
+ bp->set_mac_pending++;
+ smp_wmb();
+
bnx2x_sp_post(bp, RAMROD_CMD_ID_ETH_SET_MAC, 0,
U64_HI(bnx2x_sp_mapping(bp, mcast_config)),
U64_LO(bnx2x_sp_mapping(bp, mcast_config)),
@@ -11386,9 +11448,9 @@ static int bnx2x_change_mac_addr(struct net_device *dev, void *p)
memcpy(dev->dev_addr, addr->sa_data, dev->addr_len);
if (netif_running(dev)) {
if (CHIP_IS_E1(bp))
- bnx2x_set_mac_addr_e1(bp, 1);
+ bnx2x_set_eth_mac_addr_e1(bp, 1);
else
- bnx2x_set_mac_addr_e1h(bp, 1);
+ bnx2x_set_eth_mac_addr_e1h(bp, 1);
}
return 0;
--
1.6.4.GIT
^ permalink raw reply related
* [PATCH 4/7] bnx2x: Add main CNIC interface functions.
From: Michael Chan @ 2009-10-10 23:46 UTC (permalink / raw)
To: davem; +Cc: netdev, michaelc, shmulikr, eilong, Michael Chan
In-Reply-To: <1255218419-17320-1-git-send-email-mchan@broadcom.com>
Add the main CNIC registration, callback, MAC addr. setup functions.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Shmulik Ravid - Rabinovitz <shmulikr@broadcom.com>
Acked-by: Eilon Greenstein <eilong@broadcom.com>
---
drivers/net/bnx2x.h | 4 +
drivers/net/bnx2x_main.c | 388 ++++++++++++++++++++++++++++++++++++++++++++++
drivers/net/cnic_if.h | 14 ++-
3 files changed, 404 insertions(+), 2 deletions(-)
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index e94ce83..60fa14f 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -24,6 +24,10 @@
#define BCM_VLAN 1
#endif
+#if defined(CONFIG_CNIC) || defined(CONFIG_CNIC_MODULE)
+#define BCM_CNIC 1
+#include "cnic_if.h"
+#endif
#define BNX2X_MULTI_QUEUE
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index f7b7110..b4e9c6e 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -969,6 +969,9 @@ static void bnx2x_tx_int(struct bnx2x_fastpath *fp)
}
}
+#ifdef BCM_CNIC
+static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid);
+#endif
static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
union eth_rx_cqe *rr_cqe)
@@ -1025,6 +1028,12 @@ static void bnx2x_sp_event(struct bnx2x_fastpath *fp,
bnx2x_fp(bp, cid, state) = BNX2X_FP_STATE_CLOSED;
break;
+#ifdef BCM_CNIC
+ case (RAMROD_CMD_ID_ETH_CFC_DEL | BNX2X_STATE_OPEN):
+ DP(NETIF_MSG_IFDOWN, "got delete ramrod for CID %d\n", cid);
+ bnx2x_cnic_cfc_comp(bp, cid);
+ break;
+#endif
case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_OPEN):
case (RAMROD_CMD_ID_ETH_SET_MAC | BNX2X_STATE_DIAG):
@@ -1810,6 +1819,20 @@ static irqreturn_t bnx2x_interrupt(int irq, void *dev_instance)
}
}
+#ifdef BCM_CNIC
+ mask = 0x2 << CNIC_SB_ID(bp);
+ if (status & (mask | 0x1)) {
+ struct cnic_ops *c_ops = NULL;
+
+ rcu_read_lock();
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops)
+ c_ops->cnic_handler(bp->cnic_data, NULL);
+ rcu_read_unlock();
+
+ status &= ~mask;
+ }
+#endif
if (unlikely(status & 0x1)) {
queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
@@ -3247,6 +3270,17 @@ static irqreturn_t bnx2x_msix_sp_int(int irq, void *dev_instance)
return IRQ_HANDLED;
#endif
+#ifdef BCM_CNIC
+ {
+ struct cnic_ops *c_ops;
+
+ rcu_read_lock();
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops)
+ c_ops->cnic_handler(bp->cnic_data, NULL);
+ rcu_read_unlock();
+ }
+#endif
queue_delayed_work(bnx2x_wq, &bp->sp_task, 0);
return IRQ_HANDLED;
@@ -7291,6 +7325,44 @@ static void bnx2x_set_eth_mac_addr_e1(struct bnx2x *bp, int set)
bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
}
+#ifdef BCM_CNIC
+/**
+ * Set iSCSI MAC(s) at the next enties in the CAM after the ETH
+ * MAC(s). This function will wait until the ramdord completion
+ * returns.
+ *
+ * @param bp driver handle
+ * @param set set or clear the CAM entry
+ *
+ * @return 0 if cussess, -ENODEV if ramrod doesn't return.
+ */
+static int bnx2x_set_iscsi_eth_mac_addr(struct bnx2x *bp, int set)
+{
+ u32 cl_bit_vec = (1 << BCM_ISCSI_ETH_CL_ID);
+
+ bp->set_mac_pending++;
+ smp_wmb();
+
+ /* Send a SET_MAC ramrod */
+ if (CHIP_IS_E1(bp))
+ bnx2x_set_mac_addr_e1_gen(bp, set, bp->iscsi_mac,
+ cl_bit_vec, (BP_PORT(bp) ? 32 : 0) + 2,
+ 1);
+ else
+ /* CAM allocation for E1H
+ * unicasts: by func number
+ * multicast: 20+FUNC*20, 20 each
+ */
+ bnx2x_set_mac_addr_e1h_gen(bp, set, bp->iscsi_mac,
+ cl_bit_vec, E1H_FUNC_MAX + BP_FUNC(bp));
+
+ /* Wait for a completion when setting */
+ bnx2x_wait_ramrod(bp, 0, 0, &bp->set_mac_pending, set ? 0 : 1);
+
+ return 0;
+}
+#endif
+
static int bnx2x_setup_leading(struct bnx2x *bp)
{
int rc;
@@ -7416,6 +7488,10 @@ static int bnx2x_set_int_mode(struct bnx2x *bp)
return rc;
}
+#ifdef BCM_CNIC
+static int bnx2x_cnic_notify(struct bnx2x *bp, int cmd);
+static void bnx2x_setup_cnic_irq_info(struct bnx2x *bp);
+#endif
/* must be called with rtnl_lock */
static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
@@ -7576,6 +7652,15 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
bnx2x_set_eth_mac_addr_e1(bp, 1);
else
bnx2x_set_eth_mac_addr_e1h(bp, 1);
+#ifdef BCM_CNIC
+ /* Set iSCSI L2 MAC */
+ mutex_lock(&bp->cnic_mutex);
+ if (bp->cnic_eth_dev.drv_state & CNIC_DRV_STATE_REGD) {
+ bnx2x_set_iscsi_eth_mac_addr(bp, 1);
+ bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
+ }
+ mutex_unlock(&bp->cnic_mutex);
+#endif
}
if (bp->port.pmf)
@@ -7616,6 +7701,11 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
/* start the timer */
mod_timer(&bp->timer, jiffies + bp->current_interval);
+#ifdef BCM_CNIC
+ bnx2x_setup_cnic_irq_info(bp);
+ if (bp->state == BNX2X_STATE_OPEN)
+ bnx2x_cnic_notify(bp, CNIC_CTL_START_CMD);
+#endif
return 0;
@@ -7810,6 +7900,9 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
u32 reset_code = 0;
int i, cnt, rc;
+#ifdef BCM_CNIC
+ bnx2x_cnic_notify(bp, CNIC_CTL_STOP_CMD);
+#endif
bp->state = BNX2X_STATE_CLOSING_WAIT4_HALT;
/* Set "drop all" */
@@ -7886,6 +7979,15 @@ static int bnx2x_nic_unload(struct bnx2x *bp, int unload_mode)
REG_WR(bp, MISC_REG_E1HMF_MODE, 0);
}
+#ifdef BCM_CNIC
+ /* Clear iSCSI L2 MAC */
+ mutex_lock(&bp->cnic_mutex);
+ if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
+ bnx2x_set_iscsi_eth_mac_addr(bp, 0);
+ bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
+ }
+ mutex_unlock(&bp->cnic_mutex);
+#endif
if (unload_mode == UNLOAD_NORMAL)
reset_code = DRV_MSG_CODE_UNLOAD_REQ_WOL_DIS;
@@ -8855,6 +8957,9 @@ static int __devinit bnx2x_init_bp(struct bnx2x *bp)
smp_wmb(); /* Ensure that bp->intr_sem update is SMP-safe */
mutex_init(&bp->port.phy_mutex);
+#ifdef BCM_CNIC
+ mutex_init(&bp->cnic_mutex);
+#endif
INIT_DELAYED_WORK(&bp->sp_task, bnx2x_sp_task);
INIT_WORK(&bp->reset_task, bnx2x_reset_task);
@@ -12448,4 +12553,287 @@ static void __exit bnx2x_cleanup(void)
module_init(bnx2x_init);
module_exit(bnx2x_cleanup);
+#ifdef BCM_CNIC
+
+/* count denotes the number of new completions we have seen */
+static void bnx2x_cnic_sp_post(struct bnx2x *bp, int count)
+{
+ struct eth_spe *spe;
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (unlikely(bp->panic))
+ return;
+#endif
+
+ spin_lock_bh(&bp->spq_lock);
+ bp->cnic_spq_pending -= count;
+
+ for (; bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending;
+ bp->cnic_spq_pending++) {
+
+ if (!bp->cnic_kwq_pending)
+ break;
+
+ spe = bnx2x_sp_get_next(bp);
+ *spe = *bp->cnic_kwq_cons;
+
+ bp->cnic_kwq_pending--;
+
+ DP(NETIF_MSG_TIMER, "pending on SPQ %d, on KWQ %d count %d\n",
+ bp->cnic_spq_pending, bp->cnic_kwq_pending, count);
+
+ if (bp->cnic_kwq_cons == bp->cnic_kwq_last)
+ bp->cnic_kwq_cons = bp->cnic_kwq;
+ else
+ bp->cnic_kwq_cons++;
+ }
+ bnx2x_sp_prod_update(bp);
+ spin_unlock_bh(&bp->spq_lock);
+}
+
+static int bnx2x_cnic_sp_queue(struct net_device *dev,
+ struct kwqe_16 *kwqes[], u32 count)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int i;
+
+#ifdef BNX2X_STOP_ON_ERROR
+ if (unlikely(bp->panic))
+ return -EIO;
+#endif
+
+ spin_lock_bh(&bp->spq_lock);
+
+ for (i = 0; i < count; i++) {
+ struct eth_spe *spe = (struct eth_spe *)kwqes[i];
+
+ if (bp->cnic_kwq_pending == MAX_SP_DESC_CNT)
+ break;
+
+ *bp->cnic_kwq_prod = *spe;
+
+ bp->cnic_kwq_pending++;
+
+ DP(NETIF_MSG_TIMER, "L5 SPQE %x %x %x:%x pos %d\n",
+ spe->hdr.conn_and_cmd_data, spe->hdr.type,
+ spe->data.mac_config_addr.hi,
+ spe->data.mac_config_addr.lo,
+ bp->cnic_kwq_pending);
+
+ if (bp->cnic_kwq_prod == bp->cnic_kwq_last)
+ bp->cnic_kwq_prod = bp->cnic_kwq;
+ else
+ bp->cnic_kwq_prod++;
+ }
+
+ spin_unlock_bh(&bp->spq_lock);
+
+ if (bp->cnic_spq_pending < bp->cnic_eth_dev.max_kwqe_pending)
+ bnx2x_cnic_sp_post(bp, 0);
+
+ return i;
+}
+
+static int bnx2x_cnic_ctl_send(struct bnx2x *bp, struct cnic_ctl_info *ctl)
+{
+ struct cnic_ops *c_ops;
+ int rc = 0;
+
+ mutex_lock(&bp->cnic_mutex);
+ c_ops = bp->cnic_ops;
+ if (c_ops)
+ rc = c_ops->cnic_ctl(bp->cnic_data, ctl);
+ mutex_unlock(&bp->cnic_mutex);
+
+ return rc;
+}
+
+static int bnx2x_cnic_ctl_send_bh(struct bnx2x *bp, struct cnic_ctl_info *ctl)
+{
+ struct cnic_ops *c_ops;
+ int rc = 0;
+
+ rcu_read_lock();
+ c_ops = rcu_dereference(bp->cnic_ops);
+ if (c_ops)
+ rc = c_ops->cnic_ctl(bp->cnic_data, ctl);
+ rcu_read_unlock();
+
+ return rc;
+}
+
+/*
+ * for commands that have no data
+ */
+static int bnx2x_cnic_notify(struct bnx2x *bp, int cmd)
+{
+ struct cnic_ctl_info ctl = {0};
+
+ ctl.cmd = cmd;
+
+ return bnx2x_cnic_ctl_send(bp, &ctl);
+}
+
+static void bnx2x_cnic_cfc_comp(struct bnx2x *bp, int cid)
+{
+ struct cnic_ctl_info ctl;
+
+ /* first we tell CNIC and only then we count this as a completion */
+ ctl.cmd = CNIC_CTL_COMPLETION_CMD;
+ ctl.data.comp.cid = cid;
+
+ bnx2x_cnic_ctl_send_bh(bp, &ctl);
+ bnx2x_cnic_sp_post(bp, 1);
+}
+
+static int bnx2x_drv_ctl(struct net_device *dev, struct drv_ctl_info *ctl)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ int rc = 0;
+
+ switch (ctl->cmd) {
+ case DRV_CTL_CTXTBL_WR_CMD: {
+ u32 index = ctl->data.io.offset;
+ dma_addr_t addr = ctl->data.io.dma_addr;
+
+ bnx2x_ilt_wr(bp, index, addr);
+ break;
+ }
+
+ case DRV_CTL_COMPLETION_CMD: {
+ int count = ctl->data.comp.comp_count;
+
+ bnx2x_cnic_sp_post(bp, count);
+ break;
+ }
+
+ /* rtnl_lock is held. */
+ case DRV_CTL_START_L2_CMD: {
+ u32 cli = ctl->data.ring.client_id;
+
+ bp->rx_mode_cl_mask |= (1 << cli);
+ bnx2x_set_storm_rx_mode(bp);
+ break;
+ }
+
+ /* rtnl_lock is held. */
+ case DRV_CTL_STOP_L2_CMD: {
+ u32 cli = ctl->data.ring.client_id;
+
+ bp->rx_mode_cl_mask &= ~(1 << cli);
+ bnx2x_set_storm_rx_mode(bp);
+ break;
+ }
+
+ default:
+ BNX2X_ERR("unknown command %x\n", ctl->cmd);
+ rc = -EINVAL;
+ }
+
+ return rc;
+}
+
+static void bnx2x_setup_cnic_irq_info(struct bnx2x *bp)
+{
+ struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+ if (bp->flags & USING_MSIX_FLAG) {
+ cp->drv_state |= CNIC_DRV_STATE_USING_MSIX;
+ cp->irq_arr[0].irq_flags |= CNIC_IRQ_FL_MSIX;
+ cp->irq_arr[0].vector = bp->msix_table[1].vector;
+ } else {
+ cp->drv_state &= ~CNIC_DRV_STATE_USING_MSIX;
+ cp->irq_arr[0].irq_flags &= ~CNIC_IRQ_FL_MSIX;
+ }
+ cp->irq_arr[0].status_blk = bp->cnic_sb;
+ cp->irq_arr[0].status_blk_num = CNIC_SB_ID(bp);
+ cp->irq_arr[1].status_blk = bp->def_status_blk;
+ cp->irq_arr[1].status_blk_num = DEF_SB_ID;
+
+ cp->num_irq = 2;
+}
+
+static int bnx2x_register_cnic(struct net_device *dev, struct cnic_ops *ops,
+ void *data)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+ if (ops == NULL)
+ return -EINVAL;
+
+ if (atomic_read(&bp->intr_sem) != 0)
+ return -EBUSY;
+
+ bp->cnic_kwq = kzalloc(PAGE_SIZE, GFP_KERNEL);
+ if (!bp->cnic_kwq)
+ return -ENOMEM;
+
+ bp->cnic_kwq_cons = bp->cnic_kwq;
+ bp->cnic_kwq_prod = bp->cnic_kwq;
+ bp->cnic_kwq_last = bp->cnic_kwq + MAX_SP_DESC_CNT;
+
+ bp->cnic_spq_pending = 0;
+ bp->cnic_kwq_pending = 0;
+
+ bp->cnic_data = data;
+
+ cp->num_irq = 0;
+ cp->drv_state = CNIC_DRV_STATE_REGD;
+
+ bnx2x_init_sb(bp, bp->cnic_sb, bp->cnic_sb_mapping, CNIC_SB_ID(bp));
+
+ bnx2x_setup_cnic_irq_info(bp);
+ bnx2x_set_iscsi_eth_mac_addr(bp, 1);
+ bp->cnic_flags |= BNX2X_CNIC_FLAG_MAC_SET;
+ rcu_assign_pointer(bp->cnic_ops, ops);
+
+ return 0;
+}
+
+static int bnx2x_unregister_cnic(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+ mutex_lock(&bp->cnic_mutex);
+ if (bp->cnic_flags & BNX2X_CNIC_FLAG_MAC_SET) {
+ bp->cnic_flags &= ~BNX2X_CNIC_FLAG_MAC_SET;
+ bnx2x_set_iscsi_eth_mac_addr(bp, 0);
+ }
+ cp->drv_state = 0;
+ rcu_assign_pointer(bp->cnic_ops, NULL);
+ mutex_unlock(&bp->cnic_mutex);
+ synchronize_rcu();
+ kfree(bp->cnic_kwq);
+ bp->cnic_kwq = NULL;
+
+ return 0;
+}
+
+struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev)
+{
+ struct bnx2x *bp = netdev_priv(dev);
+ struct cnic_eth_dev *cp = &bp->cnic_eth_dev;
+
+ cp->drv_owner = THIS_MODULE;
+ cp->chip_id = CHIP_ID(bp);
+ cp->pdev = bp->pdev;
+ cp->io_base = bp->regview;
+ cp->io_base2 = bp->doorbells;
+ cp->max_kwqe_pending = 8;
+ cp->ctx_blk_size = CNIC_CTX_PER_ILT * sizeof(union cdu_context);
+ cp->ctx_tbl_offset = FUNC_ILT_BASE(BP_FUNC(bp)) + 1;
+ cp->ctx_tbl_len = CNIC_ILT_LINES;
+ cp->starting_cid = BCM_CNIC_CID_START;
+ cp->drv_submit_kwqes_16 = bnx2x_cnic_sp_queue;
+ cp->drv_ctl = bnx2x_drv_ctl;
+ cp->drv_register_cnic = bnx2x_register_cnic;
+ cp->drv_unregister_cnic = bnx2x_unregister_cnic;
+
+ return cp;
+}
+EXPORT_SYMBOL(bnx2x_cnic_probe);
+
+#endif /* BCM_CNIC */
diff --git a/drivers/net/cnic_if.h b/drivers/net/cnic_if.h
index d8b09ef..8aaf98b 100644
--- a/drivers/net/cnic_if.h
+++ b/drivers/net/cnic_if.h
@@ -12,8 +12,8 @@
#ifndef CNIC_IF_H
#define CNIC_IF_H
-#define CNIC_MODULE_VERSION "2.0.1"
-#define CNIC_MODULE_RELDATE "Oct 01, 2009"
+#define CNIC_MODULE_VERSION "2.1.0"
+#define CNIC_MODULE_RELDATE "Oct 10, 2009"
#define CNIC_ULP_RDMA 0
#define CNIC_ULP_ISCSI 1
@@ -81,6 +81,8 @@ struct kcqe {
#define DRV_CTL_CTX_WR_CMD 0x103
#define DRV_CTL_CTXTBL_WR_CMD 0x104
#define DRV_CTL_COMPLETION_CMD 0x105
+#define DRV_CTL_START_L2_CMD 0x106
+#define DRV_CTL_STOP_L2_CMD 0x107
struct cnic_ctl_completion {
u32 cid;
@@ -105,11 +107,17 @@ struct drv_ctl_io {
dma_addr_t dma_addr;
};
+struct drv_ctl_l2_ring {
+ u32 client_id;
+ u32 cid;
+};
+
struct drv_ctl_info {
int cmd;
union {
struct drv_ctl_completion comp;
struct drv_ctl_io io;
+ struct drv_ctl_l2_ring ring;
char bytes[MAX_DRV_CTL_DATA];
} data;
};
@@ -143,6 +151,7 @@ struct cnic_eth_dev {
u32 max_kwqe_pending;
struct pci_dev *pdev;
void __iomem *io_base;
+ void __iomem *io_base2;
u32 ctx_tbl_offset;
u32 ctx_tbl_len;
@@ -298,5 +307,6 @@ extern int cnic_register_driver(int ulp_type, struct cnic_ulp_ops *ulp_ops);
extern int cnic_unregister_driver(int ulp_type);
extern struct cnic_eth_dev *bnx2_cnic_probe(struct net_device *dev);
+extern struct cnic_eth_dev *bnx2x_cnic_probe(struct net_device *dev);
#endif
--
1.6.4.GIT
^ permalink raw reply related
* [PATCH 5/7] cnic: Refactor some code.
From: Michael Chan @ 2009-10-10 23:46 UTC (permalink / raw)
To: davem; +Cc: netdev, michaelc, shmulikr, eilong, Michael Chan
In-Reply-To: <1255218419-17320-1-git-send-email-mchan@broadcom.com>
Refactor ring init. code for subsequent 10G patches. Also add rtnl_lock()
in cnic_uio_open() to prevent race condition with netdev events.
Signed-off-by: Michael Chan <mchan@broadcom.com>
---
drivers/net/cnic.c | 64 +++++++++++++++++++++++++++++++++++++--------------
1 files changed, 46 insertions(+), 18 deletions(-)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 46c87ec..eac68f9 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -67,9 +67,8 @@ static struct cnic_ops cnic_bnx2_ops = {
.cnic_ctl = cnic_ctl,
};
-static void cnic_shutdown_bnx2_rx_ring(struct cnic_dev *);
-static void cnic_init_bnx2_tx_ring(struct cnic_dev *);
-static void cnic_init_bnx2_rx_ring(struct cnic_dev *);
+static void cnic_shutdown_rings(struct cnic_dev *);
+static void cnic_init_rings(struct cnic_dev *);
static int cnic_cm_set_pg(struct cnic_sock *);
static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode)
@@ -83,10 +82,16 @@ static int cnic_uio_open(struct uio_info *uinfo, struct inode *inode)
if (cp->uio_dev != -1)
return -EBUSY;
+ rtnl_lock();
+ if (!test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
+ rtnl_unlock();
+ return -ENODEV;
+ }
+
cp->uio_dev = iminor(inode);
- cnic_init_bnx2_tx_ring(dev);
- cnic_init_bnx2_rx_ring(dev);
+ cnic_init_rings(dev);
+ rtnl_unlock();
return 0;
}
@@ -96,7 +101,7 @@ static int cnic_uio_close(struct uio_info *uinfo, struct inode *inode)
struct cnic_dev *dev = uinfo->priv;
struct cnic_local *cp = dev->cnic_priv;
- cnic_shutdown_bnx2_rx_ring(dev);
+ cnic_shutdown_rings(dev);
cp->uio_dev = -1;
return 0;
@@ -675,6 +680,21 @@ error:
return -ENOMEM;
}
+static void cnic_free_context(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i;
+
+ for (i = 0; i < cp->ctx_blks; i++) {
+ if (cp->ctx_arr[i].ctx) {
+ pci_free_consistent(dev->pcidev, cp->ctx_blk_size,
+ cp->ctx_arr[i].ctx,
+ cp->ctx_arr[i].mapping);
+ cp->ctx_arr[i].ctx = NULL;
+ }
+ }
+}
+
static void cnic_free_resc(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -702,14 +722,7 @@ static void cnic_free_resc(struct cnic_dev *dev)
cp->l2_ring = NULL;
}
- for (i = 0; i < cp->ctx_blks; i++) {
- if (cp->ctx_arr[i].ctx) {
- pci_free_consistent(dev->pcidev, cp->ctx_blk_size,
- cp->ctx_arr[i].ctx,
- cp->ctx_arr[i].mapping);
- cp->ctx_arr[i].ctx = NULL;
- }
- }
+ cnic_free_context(dev);
kfree(cp->ctx_arr);
cp->ctx_arr = NULL;
cp->ctx_blks = 0;
@@ -808,8 +821,8 @@ static int cnic_alloc_uio(struct cnic_dev *dev) {
uinfo->mem[0].size = dev->netdev->mem_end - dev->netdev->mem_start;
uinfo->mem[0].memtype = UIO_MEM_PHYS;
- uinfo->mem[1].addr = (unsigned long) cp->status_blk & PAGE_MASK;
if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
+ uinfo->mem[1].addr = (unsigned long) cp->status_blk & PAGE_MASK;
if (cp->ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX)
uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE * 9;
else
@@ -1012,7 +1025,7 @@ static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
return last_cnt;
}
-static void cnic_chk_bnx2_pkt_rings(struct cnic_local *cp)
+static void cnic_chk_pkt_rings(struct cnic_local *cp)
{
u16 rx_cons = *cp->rx_cons_ptr;
u16 tx_cons = *cp->tx_cons_ptr;
@@ -1062,7 +1075,7 @@ done:
cp->kcq_prod_idx = sw_prod;
- cnic_chk_bnx2_pkt_rings(cp);
+ cnic_chk_pkt_rings(cp);
return status_idx;
}
@@ -1100,7 +1113,7 @@ done:
CNIC_WR16(dev, cp->kcq_io_addr, sw_prod);
cp->kcq_prod_idx = sw_prod;
- cnic_chk_bnx2_pkt_rings(cp);
+ cnic_chk_pkt_rings(cp);
cp->last_status_idx = status_idx;
CNIC_WR(dev, BNX2_PCICFG_INT_ACK_CMD, cp->int_num |
@@ -2464,6 +2477,21 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
return 0;
}
+static void cnic_init_rings(struct cnic_dev *dev)
+{
+ if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
+ cnic_init_bnx2_tx_ring(dev);
+ cnic_init_bnx2_rx_ring(dev);
+ }
+}
+
+static void cnic_shutdown_rings(struct cnic_dev *dev)
+{
+ if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
+ cnic_shutdown_bnx2_rx_ring(dev);
+ }
+}
+
static int cnic_register_netdev(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
--
1.6.4.GIT
^ permalink raw reply related
* [PATCH 3/7] bnx2x: Add hw init code to support iSCSI.
From: Michael Chan @ 2009-10-10 23:46 UTC (permalink / raw)
To: davem; +Cc: netdev, michaelc, shmulikr, eilong, Michael Chan
In-Reply-To: <1255218419-17320-1-git-send-email-mchan@broadcom.com>
Add code to initialize hardware blocks used for iSCSI.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Shmulik Ravid - Rabinovitz <shmulikr@broadcom.com>
Acked-by: Eilon Greenstein <eilong@broadcom.com>
---
drivers/net/bnx2x.h | 59 +++++++++++---
drivers/net/bnx2x_main.c | 210 +++++++++++++++++++++++++++++++++-------------
2 files changed, 200 insertions(+), 69 deletions(-)
diff --git a/drivers/net/bnx2x.h b/drivers/net/bnx2x.h
index 1f07063..e94ce83 100644
--- a/drivers/net/bnx2x.h
+++ b/drivers/net/bnx2x.h
@@ -762,7 +762,11 @@ struct bnx2x_eth_stats {
(offsetof(struct bnx2x_eth_stats, stat_name) / 4)
+#ifdef BCM_CNIC
+#define MAX_CONTEXT 15
+#else
#define MAX_CONTEXT 16
+#endif
union cdu_context {
struct eth_context eth;
@@ -811,13 +815,21 @@ struct bnx2x {
struct bnx2x_fastpath fp[MAX_CONTEXT];
void __iomem *regview;
void __iomem *doorbells;
+#ifdef BCM_CNIC
+#define BNX2X_DB_SIZE (18*BCM_PAGE_SIZE)
+#else
#define BNX2X_DB_SIZE (16*BCM_PAGE_SIZE)
+#endif
struct net_device *dev;
struct pci_dev *pdev;
atomic_t intr_sem;
+#ifdef BCM_CNIC
+ struct msix_entry msix_table[MAX_CONTEXT+2];
+#else
struct msix_entry msix_table[MAX_CONTEXT+1];
+#endif
#define INT_MODE_INTx 1
#define INT_MODE_MSI 2
#define INT_MODE_MSIX 3
@@ -891,6 +903,11 @@ struct bnx2x {
#define BP_E1HVN(bp) (bp->func >> 1)
#define BP_L_ID(bp) (BP_E1HVN(bp) << 2)
+#ifdef BCM_CNIC
+#define BCM_CNIC_CID_START 16
+#define BCM_ISCSI_ETH_CL_ID 17
+#endif
+
int pm_cap;
int pcie_cap;
int mrrs;
@@ -960,24 +977,44 @@ struct bnx2x {
#define BNX2X_MAX_MULTICAST 64
#define BNX2X_MAX_EMUL_MULTI 16
+ u32 rx_mode_cl_mask;
+
dma_addr_t def_status_blk_mapping;
struct bnx2x_slowpath *slowpath;
dma_addr_t slowpath_mapping;
-#ifdef BCM_ISCSI
- void *t1;
- dma_addr_t t1_mapping;
- void *t2;
- dma_addr_t t2_mapping;
- void *timers;
- dma_addr_t timers_mapping;
- void *qm;
- dma_addr_t qm_mapping;
-#endif
-
int dropless_fc;
+#ifdef BCM_CNIC
+ u32 cnic_flags;
+#define BNX2X_CNIC_FLAG_MAC_SET 1
+
+ void *t1;
+ dma_addr_t t1_mapping;
+ void *t2;
+ dma_addr_t t2_mapping;
+ void *timers;
+ dma_addr_t timers_mapping;
+ void *qm;
+ dma_addr_t qm_mapping;
+ struct cnic_ops *cnic_ops;
+ void *cnic_data;
+ u32 cnic_tag;
+ struct cnic_eth_dev cnic_eth_dev;
+ struct host_status_block *cnic_sb;
+ dma_addr_t cnic_sb_mapping;
+#define CNIC_SB_ID(bp) BP_L_ID(bp)
+ struct eth_spe *cnic_kwq;
+ struct eth_spe *cnic_kwq_prod;
+ struct eth_spe *cnic_kwq_cons;
+ struct eth_spe *cnic_kwq_last;
+ u16 cnic_kwq_pending;
+ u16 cnic_spq_pending;
+ struct mutex cnic_mutex;
+ u8 iscsi_mac[6];
+#endif
+
int dmae_ready;
/* used to synchronize dmae accesses */
struct mutex dmae_mutex;
diff --git a/drivers/net/bnx2x_main.c b/drivers/net/bnx2x_main.c
index 02ce3b3..f7b7110 100644
--- a/drivers/net/bnx2x_main.c
+++ b/drivers/net/bnx2x_main.c
@@ -742,6 +742,9 @@ static void bnx2x_int_disable_sync(struct bnx2x *bp, int disable_hw)
if (msix) {
synchronize_irq(bp->msix_table[0].vector);
offset = 1;
+#ifdef BCM_CNIC
+ offset++;
+#endif
for_each_queue(bp, i)
synchronize_irq(bp->msix_table[i + offset].vector);
} else
@@ -5252,7 +5255,7 @@ static void bnx2x_set_storm_rx_mode(struct bnx2x *bp)
{
struct tstorm_eth_mac_filter_config tstorm_mac_filter = {0};
int mode = bp->rx_mode;
- int mask = (1 << BP_L_ID(bp));
+ int mask = bp->rx_mode_cl_mask;
int func = BP_FUNC(bp);
int port = BP_PORT(bp);
int i;
@@ -5365,6 +5368,7 @@ static void bnx2x_init_internal_func(struct bnx2x *bp)
(*(u32 *)&tstorm_config));
bp->rx_mode = BNX2X_RX_MODE_NONE; /* no rx until link is up */
+ bp->rx_mode_cl_mask = (1 << BP_L_ID(bp));
bnx2x_set_storm_rx_mode(bp);
for_each_queue(bp, i) {
@@ -5582,7 +5586,11 @@ static void bnx2x_nic_init(struct bnx2x *bp, u32 load_code)
fp->state = BNX2X_FP_STATE_CLOSED;
fp->index = i;
fp->cl_id = BP_L_ID(bp) + i;
+#ifdef BCM_CNIC
+ fp->sb_id = fp->cl_id + 1;
+#else
fp->sb_id = fp->cl_id;
+#endif
/* Suitable Rx and Tx SBs are served by the same client */
if (i >= bp->num_rx_queues)
fp->cl_id -= bp->num_rx_queues;
@@ -5884,7 +5892,7 @@ static int bnx2x_int_mem_test(struct bnx2x *bp)
msleep(50);
bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
-#ifndef BCM_ISCSI
+#ifndef BCM_CNIC
/* set NIC mode */
REG_WR(bp, PRS_REG_NIC_MODE, 1);
#endif
@@ -6023,6 +6031,9 @@ static void bnx2x_setup_fan_failure_detection(struct bnx2x *bp)
static int bnx2x_init_common(struct bnx2x *bp)
{
u32 val, i;
+#ifdef BCM_CNIC
+ u32 wb_write[2];
+#endif
DP(BNX2X_MSG_MCP, "starting common init func %d\n", BP_FUNC(bp));
@@ -6065,7 +6076,7 @@ static int bnx2x_init_common(struct bnx2x *bp)
#endif
REG_WR(bp, PXP2_REG_RQ_CDU_P_SIZE, 2);
-#ifdef BCM_ISCSI
+#ifdef BCM_CNIC
REG_WR(bp, PXP2_REG_RQ_TM_P_SIZE, 5);
REG_WR(bp, PXP2_REG_RQ_QM_P_SIZE, 5);
REG_WR(bp, PXP2_REG_RQ_SRC_P_SIZE, 5);
@@ -6108,11 +6119,26 @@ static int bnx2x_init_common(struct bnx2x *bp)
bnx2x_read_dmae(bp, USEM_REG_PASSIVE_BUFFER, 3);
bnx2x_init_block(bp, QM_BLOCK, COMMON_STAGE);
+
+#ifdef BCM_CNIC
+ wb_write[0] = 0;
+ wb_write[1] = 0;
+ for (i = 0; i < 64; i++) {
+ REG_WR(bp, QM_REG_BASEADDR + i*4, 1024 * 4 * (i%16));
+ bnx2x_init_ind_wr(bp, QM_REG_PTRTBL + i*8, wb_write, 2);
+
+ if (CHIP_IS_E1H(bp)) {
+ REG_WR(bp, QM_REG_BASEADDR_EXT_A + i*4, 1024*4*(i%16));
+ bnx2x_init_ind_wr(bp, QM_REG_PTRTBL_EXT_A + i*8,
+ wb_write, 2);
+ }
+ }
+#endif
/* soft reset pulse */
REG_WR(bp, QM_REG_SOFT_RESET, 1);
REG_WR(bp, QM_REG_SOFT_RESET, 0);
-#ifdef BCM_ISCSI
+#ifdef BCM_CNIC
bnx2x_init_block(bp, TIMERS_BLOCK, COMMON_STAGE);
#endif
@@ -6126,8 +6152,10 @@ static int bnx2x_init_common(struct bnx2x *bp)
bnx2x_init_block(bp, BRB1_BLOCK, COMMON_STAGE);
bnx2x_init_block(bp, PRS_BLOCK, COMMON_STAGE);
REG_WR(bp, PRS_REG_A_PRSU_20, 0xf);
+#ifndef BCM_CNIC
/* set NIC mode */
REG_WR(bp, PRS_REG_NIC_MODE, 1);
+#endif
if (CHIP_IS_E1H(bp))
REG_WR(bp, PRS_REG_E1HOV_MODE, IS_E1HMF(bp));
@@ -6162,6 +6190,18 @@ static int bnx2x_init_common(struct bnx2x *bp)
/* TODO: replace with something meaningful */
}
bnx2x_init_block(bp, SRCH_BLOCK, COMMON_STAGE);
+#ifdef BCM_CNIC
+ REG_WR(bp, SRC_REG_KEYSEARCH_0, 0x63285672);
+ REG_WR(bp, SRC_REG_KEYSEARCH_1, 0x24b8f2cc);
+ REG_WR(bp, SRC_REG_KEYSEARCH_2, 0x223aef9b);
+ REG_WR(bp, SRC_REG_KEYSEARCH_3, 0x26001e3a);
+ REG_WR(bp, SRC_REG_KEYSEARCH_4, 0x7ae91116);
+ REG_WR(bp, SRC_REG_KEYSEARCH_5, 0x5ce5230b);
+ REG_WR(bp, SRC_REG_KEYSEARCH_6, 0x298d8adf);
+ REG_WR(bp, SRC_REG_KEYSEARCH_7, 0x6eb0ff09);
+ REG_WR(bp, SRC_REG_KEYSEARCH_8, 0x1830f82f);
+ REG_WR(bp, SRC_REG_KEYSEARCH_9, 0x01e46be7);
+#endif
REG_WR(bp, SRC_REG_SOFT_RST, 0);
if (sizeof(union cdu_context) != 1024)
@@ -6278,38 +6318,14 @@ static int bnx2x_init_port(struct bnx2x *bp)
bnx2x_init_block(bp, TCM_BLOCK, init_stage);
bnx2x_init_block(bp, UCM_BLOCK, init_stage);
bnx2x_init_block(bp, CCM_BLOCK, init_stage);
-#ifdef BCM_ISCSI
- /* Port0 1
- * Port1 385 */
- i++;
- wb_write[0] = ONCHIP_ADDR1(bp->timers_mapping);
- wb_write[1] = ONCHIP_ADDR2(bp->timers_mapping);
- REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
- REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i));
-
- /* Port0 2
- * Port1 386 */
- i++;
- wb_write[0] = ONCHIP_ADDR1(bp->qm_mapping);
- wb_write[1] = ONCHIP_ADDR2(bp->qm_mapping);
- REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
- REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i));
-
- /* Port0 3
- * Port1 387 */
- i++;
- wb_write[0] = ONCHIP_ADDR1(bp->t1_mapping);
- wb_write[1] = ONCHIP_ADDR2(bp->t1_mapping);
- REG_WR_DMAE(bp, PXP2_REG_RQ_ONCHIP_AT + i*8, wb_write, 2);
- REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i));
-#endif
bnx2x_init_block(bp, XCM_BLOCK, init_stage);
-#ifdef BCM_ISCSI
- REG_WR(bp, TM_REG_LIN0_SCAN_TIME + func*4, 1024/64*20);
- REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + func*4, 31);
+#ifdef BCM_CNIC
+ REG_WR(bp, QM_REG_CONNNUM_0 + port*4, 1024/16 - 1);
bnx2x_init_block(bp, TIMERS_BLOCK, init_stage);
+ REG_WR(bp, TM_REG_LIN0_SCAN_TIME + port*4, 20);
+ REG_WR(bp, TM_REG_LIN0_MAX_ACTIVE_CID + port*4, 31);
#endif
bnx2x_init_block(bp, DQ_BLOCK, init_stage);
@@ -6367,18 +6383,8 @@ static int bnx2x_init_port(struct bnx2x *bp)
msleep(5);
REG_WR(bp, PBF_REG_INIT_P0 + port*4, 0);
-#ifdef BCM_ISCSI
- /* tell the searcher where the T2 table is */
- REG_WR(bp, SRC_REG_COUNTFREE0 + func*4, 16*1024/64);
-
- wb_write[0] = U64_LO(bp->t2_mapping);
- wb_write[1] = U64_HI(bp->t2_mapping);
- REG_WR_DMAE(bp, SRC_REG_FIRSTFREE0 + func*4, wb_write, 2);
- wb_write[0] = U64_LO((u64)bp->t2_mapping + 16*1024 - 64);
- wb_write[1] = U64_HI((u64)bp->t2_mapping + 16*1024 - 64);
- REG_WR_DMAE(bp, SRC_REG_LASTFREE0 + func*4, wb_write, 2);
-
- REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + func*4, 10);
+#ifdef BCM_CNIC
+ bnx2x_init_block(bp, SRCH_BLOCK, init_stage);
#endif
bnx2x_init_block(bp, CDU_BLOCK, init_stage);
bnx2x_init_block(bp, CFC_BLOCK, init_stage);
@@ -6487,7 +6493,12 @@ static int bnx2x_init_port(struct bnx2x *bp)
#define PXP_ONE_ILT(x) (((x) << 10) | x)
#define PXP_ILT_RANGE(f, l) (((l) << 10) | f)
+#ifdef BCM_CNIC
+#define CNIC_ILT_LINES 127
+#define CNIC_CTX_PER_ILT 16
+#else
#define CNIC_ILT_LINES 0
+#endif
static void bnx2x_ilt_wr(struct bnx2x *bp, u32 index, dma_addr_t addr)
{
@@ -6526,6 +6537,46 @@ static int bnx2x_init_func(struct bnx2x *bp)
REG_WR(bp, PXP2_REG_PSWRQ_CDU0_L2P + func*4,
PXP_ILT_RANGE(i, i + CNIC_ILT_LINES));
+#ifdef BCM_CNIC
+ i += 1 + CNIC_ILT_LINES;
+ bnx2x_ilt_wr(bp, i, bp->timers_mapping);
+ if (CHIP_IS_E1(bp))
+ REG_WR(bp, PXP2_REG_PSWRQ_TM0_L2P + func*4, PXP_ONE_ILT(i));
+ else {
+ REG_WR(bp, PXP2_REG_RQ_TM_FIRST_ILT, i);
+ REG_WR(bp, PXP2_REG_RQ_TM_LAST_ILT, i);
+ }
+
+ i++;
+ bnx2x_ilt_wr(bp, i, bp->qm_mapping);
+ if (CHIP_IS_E1(bp))
+ REG_WR(bp, PXP2_REG_PSWRQ_QM0_L2P + func*4, PXP_ONE_ILT(i));
+ else {
+ REG_WR(bp, PXP2_REG_RQ_QM_FIRST_ILT, i);
+ REG_WR(bp, PXP2_REG_RQ_QM_LAST_ILT, i);
+ }
+
+ i++;
+ bnx2x_ilt_wr(bp, i, bp->t1_mapping);
+ if (CHIP_IS_E1(bp))
+ REG_WR(bp, PXP2_REG_PSWRQ_SRC0_L2P + func*4, PXP_ONE_ILT(i));
+ else {
+ REG_WR(bp, PXP2_REG_RQ_SRC_FIRST_ILT, i);
+ REG_WR(bp, PXP2_REG_RQ_SRC_LAST_ILT, i);
+ }
+
+ /* tell the searcher where the T2 table is */
+ REG_WR(bp, SRC_REG_COUNTFREE0 + port*4, 16*1024/64);
+
+ bnx2x_wb_wr(bp, SRC_REG_FIRSTFREE0 + port*16,
+ U64_LO(bp->t2_mapping), U64_HI(bp->t2_mapping));
+
+ bnx2x_wb_wr(bp, SRC_REG_LASTFREE0 + port*16,
+ U64_LO((u64)bp->t2_mapping + 16*1024 - 64),
+ U64_HI((u64)bp->t2_mapping + 16*1024 - 64));
+
+ REG_WR(bp, SRC_REG_NUMBER_HASH_BITS0 + port*4, 10);
+#endif
if (CHIP_IS_E1H(bp)) {
bnx2x_init_block(bp, MISC_BLOCK, FUNC0_STAGE + func);
@@ -6610,6 +6661,9 @@ static int bnx2x_init_hw(struct bnx2x *bp, u32 load_code)
bnx2x_zero_def_sb(bp);
for_each_queue(bp, i)
bnx2x_zero_sb(bp, BP_L_ID(bp) + i);
+#ifdef BCM_CNIC
+ bnx2x_zero_sb(bp, BP_L_ID(bp) + i);
+#endif
init_hw_err:
bnx2x_gunzip_end(bp);
@@ -6685,11 +6739,13 @@ static void bnx2x_free_mem(struct bnx2x *bp)
BNX2X_PCI_FREE(bp->slowpath, bp->slowpath_mapping,
sizeof(struct bnx2x_slowpath));
-#ifdef BCM_ISCSI
+#ifdef BCM_CNIC
BNX2X_PCI_FREE(bp->t1, bp->t1_mapping, 64*1024);
BNX2X_PCI_FREE(bp->t2, bp->t2_mapping, 16*1024);
BNX2X_PCI_FREE(bp->timers, bp->timers_mapping, 8*1024);
BNX2X_PCI_FREE(bp->qm, bp->qm_mapping, 128*1024);
+ BNX2X_PCI_FREE(bp->cnic_sb, bp->cnic_sb_mapping,
+ sizeof(struct host_status_block));
#endif
BNX2X_PCI_FREE(bp->spq, bp->spq_mapping, BCM_PAGE_SIZE);
@@ -6768,32 +6824,26 @@ static int bnx2x_alloc_mem(struct bnx2x *bp)
BNX2X_PCI_ALLOC(bp->slowpath, &bp->slowpath_mapping,
sizeof(struct bnx2x_slowpath));
-#ifdef BCM_ISCSI
+#ifdef BCM_CNIC
BNX2X_PCI_ALLOC(bp->t1, &bp->t1_mapping, 64*1024);
- /* Initialize T1 */
- for (i = 0; i < 64*1024; i += 64) {
- *(u64 *)((char *)bp->t1 + i + 56) = 0x0UL;
- *(u64 *)((char *)bp->t1 + i + 3) = 0x0UL;
- }
-
/* allocate searcher T2 table
we allocate 1/4 of alloc num for T2
(which is not entered into the ILT) */
BNX2X_PCI_ALLOC(bp->t2, &bp->t2_mapping, 16*1024);
- /* Initialize T2 */
+ /* Initialize T2 (for 1024 connections) */
for (i = 0; i < 16*1024; i += 64)
- * (u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
-
- /* now fixup the last line in the block to point to the next block */
- *(u64 *)((char *)bp->t2 + 1024*16-8) = bp->t2_mapping;
+ *(u64 *)((char *)bp->t2 + i + 56) = bp->t2_mapping + i + 64;
- /* Timer block array (MAX_CONN*8) phys uncached for now 1024 conns */
+ /* Timer block array (8*MAX_CONN) phys uncached for now 1024 conns */
BNX2X_PCI_ALLOC(bp->timers, &bp->timers_mapping, 8*1024);
/* QM queues (128*MAX_CONN) */
BNX2X_PCI_ALLOC(bp->qm, &bp->qm_mapping, 128*1024);
+
+ BNX2X_PCI_ALLOC(bp->cnic_sb, &bp->cnic_sb_mapping,
+ sizeof(struct host_status_block));
#endif
/* Slow path ring */
@@ -6869,6 +6919,9 @@ static void bnx2x_free_msix_irqs(struct bnx2x *bp)
DP(NETIF_MSG_IFDOWN, "released sp irq (%d)\n",
bp->msix_table[0].vector);
+#ifdef BCM_CNIC
+ offset++;
+#endif
for_each_queue(bp, i) {
DP(NETIF_MSG_IFDOWN, "about to release fp #%d->%d irq "
"state %x\n", i, bp->msix_table[i + offset].vector,
@@ -6902,6 +6955,12 @@ static int bnx2x_enable_msix(struct bnx2x *bp)
bp->msix_table[0].entry = igu_vec;
DP(NETIF_MSG_IFUP, "msix_table[0].entry = %d (slowpath)\n", igu_vec);
+#ifdef BCM_CNIC
+ igu_vec = BP_L_ID(bp) + offset;
+ bp->msix_table[1].entry = igu_vec;
+ DP(NETIF_MSG_IFUP, "msix_table[1].entry = %d (CNIC)\n", igu_vec);
+ offset++;
+#endif
for_each_queue(bp, i) {
igu_vec = BP_L_ID(bp) + offset + i;
bp->msix_table[i + offset].entry = igu_vec;
@@ -6932,6 +6991,9 @@ static int bnx2x_req_msix_irqs(struct bnx2x *bp)
return -EBUSY;
}
+#ifdef BCM_CNIC
+ offset++;
+#endif
for_each_queue(bp, i) {
struct bnx2x_fastpath *fp = &bp->fp[i];
@@ -7496,10 +7558,18 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
}
if (bp->state == BNX2X_STATE_OPEN) {
+#ifdef BCM_CNIC
+ /* Enable Timer scan */
+ REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 1);
+#endif
for_each_nondefault_queue(bp, i) {
rc = bnx2x_setup_multi(bp, i);
if (rc)
+#ifdef BCM_CNIC
+ goto load_error4;
+#else
goto load_error3;
+#endif
}
if (CHIP_IS_E1(bp))
@@ -7549,6 +7619,11 @@ static int bnx2x_nic_load(struct bnx2x *bp, int load_mode)
return 0;
+#ifdef BCM_CNIC
+load_error4:
+ /* Disable Timer scan */
+ REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + BP_PORT(bp)*4, 0);
+#endif
load_error3:
bnx2x_int_disable_sync(bp, 1);
if (!BP_NOMCP(bp)) {
@@ -7656,6 +7731,19 @@ static void bnx2x_reset_func(struct bnx2x *bp)
REG_WR(bp, HC_REG_LEADING_EDGE_0 + port*8, 0);
REG_WR(bp, HC_REG_TRAILING_EDGE_0 + port*8, 0);
+#ifdef BCM_CNIC
+ /* Disable Timer scan */
+ REG_WR(bp, TM_REG_EN_LINEAR0_TIMER + port*4, 0);
+ /*
+ * Wait for at least 10ms and up to 2 second for the timers scan to
+ * complete
+ */
+ for (i = 0; i < 200; i++) {
+ msleep(10);
+ if (!REG_RD(bp, TM_REG_LIN0_SCAN_ON + port*4))
+ break;
+ }
+#endif
/* Clear ILT */
base = FUNC_ILT_BASE(func);
for (i = base; i < base + ILT_PER_FUNC; i++)
@@ -8666,6 +8754,12 @@ static void __devinit bnx2x_get_port_hwinfo(struct bnx2x *bp)
bnx2x_set_mac_buf(bp->dev->dev_addr, val, val2);
memcpy(bp->link_params.mac_addr, bp->dev->dev_addr, ETH_ALEN);
memcpy(bp->dev->perm_addr, bp->dev->dev_addr, ETH_ALEN);
+
+#ifdef BCM_CNIC
+ val2 = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_upper);
+ val = SHMEM_RD(bp, dev_info.port_hw_config[port].iscsi_mac_lower);
+ bnx2x_set_mac_buf(bp->iscsi_mac, val, val2);
+#endif
}
static int __devinit bnx2x_get_hwinfo(struct bnx2x *bp)
--
1.6.4.GIT
^ permalink raw reply related
* [PATCH 7/7] cnic: Add main functions to support bnx2x devices.
From: Michael Chan @ 2009-10-10 23:46 UTC (permalink / raw)
To: davem; +Cc: netdev, michaelc, shmulikr, eilong, Michael Chan
In-Reply-To: <1255218419-17320-1-git-send-email-mchan@broadcom.com>
Add iSCSI support for bnx2x devices.
Signed-off-by: Michael Chan <mchan@broadcom.com>
Signed-off-by: Shmulik Ravid - Rabinovitz <shmulikr@broadcom.com>
Acked-by: Eilon Greenstein <eilong@broadcom.com>
---
drivers/net/cnic.c | 1742 ++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 1742 insertions(+), 0 deletions(-)
diff --git a/drivers/net/cnic.c b/drivers/net/cnic.c
index 1fd1058..6e7af7b 100644
--- a/drivers/net/cnic.c
+++ b/drivers/net/cnic.c
@@ -64,6 +64,7 @@ static DEFINE_MUTEX(cnic_lock);
static struct cnic_ulp_ops *cnic_ulp_tbl[MAX_CNIC_ULP_TYPE];
static int cnic_service_bnx2(void *, void *);
+static int cnic_service_bnx2x(void *, void *);
static int cnic_ctl(void *, struct cnic_ctl_info *);
static struct cnic_ops cnic_bnx2_ops = {
@@ -72,6 +73,12 @@ static struct cnic_ops cnic_bnx2_ops = {
.cnic_ctl = cnic_ctl,
};
+static struct cnic_ops cnic_bnx2x_ops = {
+ .cnic_owner = THIS_MODULE,
+ .cnic_handler = cnic_service_bnx2x,
+ .cnic_ctl = cnic_ctl,
+};
+
static void cnic_shutdown_rings(struct cnic_dev *);
static void cnic_init_rings(struct cnic_dev *);
static int cnic_cm_set_pg(struct cnic_sock *);
@@ -172,6 +179,36 @@ static void cnic_ctx_wr(struct cnic_dev *dev, u32 cid_addr, u32 off, u32 val)
ethdev->drv_ctl(dev->netdev, &info);
}
+static void cnic_ctx_tbl_wr(struct cnic_dev *dev, u32 off, dma_addr_t addr)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ struct drv_ctl_info info;
+ struct drv_ctl_io *io = &info.data.io;
+
+ info.cmd = DRV_CTL_CTXTBL_WR_CMD;
+ io->offset = off;
+ io->dma_addr = addr;
+ ethdev->drv_ctl(dev->netdev, &info);
+}
+
+static void cnic_ring_ctl(struct cnic_dev *dev, u32 cid, u32 cl_id, int start)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ struct drv_ctl_info info;
+ struct drv_ctl_l2_ring *ring = &info.data.ring;
+
+ if (start)
+ info.cmd = DRV_CTL_START_L2_CMD;
+ else
+ info.cmd = DRV_CTL_STOP_L2_CMD;
+
+ ring->cid = cid;
+ ring->client_id = cl_id;
+ ethdev->drv_ctl(dev->netdev, &info);
+}
+
static void cnic_reg_wr_ind(struct cnic_dev *dev, u32 off, u32 val)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -214,6 +251,19 @@ static void cnic_kwq_completion(struct cnic_dev *dev, u32 count)
ethdev->drv_ctl(dev->netdev, &info);
}
+static int cnic_get_l5_cid(struct cnic_local *cp, u32 cid, u32 *l5_cid)
+{
+ u32 i;
+
+ for (i = 0; i < MAX_ISCSI_TBL_SZ; i++) {
+ if (cp->ctx_tbl[i].cid == cid) {
+ *l5_cid = i;
+ return 0;
+ }
+ }
+ return -EINVAL;
+}
+
static int cnic_send_nlmsg(struct cnic_local *cp, u32 type,
struct cnic_sock *csk)
{
@@ -645,6 +695,20 @@ static void cnic_setup_page_tbl(struct cnic_dev *dev, struct cnic_dma *dma)
}
}
+static void cnic_setup_page_tbl_le(struct cnic_dev *dev, struct cnic_dma *dma)
+{
+ int i;
+ u32 *page_table = dma->pgtbl;
+
+ for (i = 0; i < dma->num_pages; i++) {
+ /* Each entry needs to be in little endian format. */
+ *page_table = dma->pg_map_arr[i] & 0xffffffff;
+ page_table++;
+ *page_table = (u32) ((u64) dma->pg_map_arr[i] >> 32);
+ page_table++;
+ }
+}
+
static int cnic_alloc_dma(struct cnic_dev *dev, struct cnic_dma *dma,
int pages, int use_pg_tbl)
{
@@ -735,6 +799,7 @@ static void cnic_free_resc(struct cnic_dev *dev)
cnic_free_dma(dev, &cp->gbl_buf_info);
cnic_free_dma(dev, &cp->conn_buf_info);
cnic_free_dma(dev, &cp->kwq_info);
+ cnic_free_dma(dev, &cp->kwq_16_data_info);
cnic_free_dma(dev, &cp->kcq_info);
kfree(cp->iscsi_tbl);
cp->iscsi_tbl = NULL;
@@ -834,6 +899,12 @@ static int cnic_alloc_uio(struct cnic_dev *dev) {
uinfo->mem[1].size = BNX2_SBLK_MSIX_ALIGN_SIZE;
uinfo->name = "bnx2_cnic";
+ } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
+ uinfo->mem[1].addr = (unsigned long) cp->bnx2x_def_status_blk &
+ PAGE_MASK;
+ uinfo->mem[1].size = sizeof(struct host_def_status_block);
+
+ uinfo->name = "bnx2x_cnic";
}
uinfo->mem[1].memtype = UIO_MEM_LOGICAL;
@@ -898,6 +969,151 @@ error:
return ret;
}
+static int cnic_alloc_bnx2x_context(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ int ctx_blk_size = cp->ethdev->ctx_blk_size;
+ int total_mem, blks, i, cid_space;
+
+ if (BNX2X_ISCSI_START_CID < ethdev->starting_cid)
+ return -EINVAL;
+
+ cid_space = MAX_ISCSI_TBL_SZ +
+ (BNX2X_ISCSI_START_CID - ethdev->starting_cid);
+
+ total_mem = BNX2X_CONTEXT_MEM_SIZE * cid_space;
+ blks = total_mem / ctx_blk_size;
+ if (total_mem % ctx_blk_size)
+ blks++;
+
+ if (blks > cp->ethdev->ctx_tbl_len)
+ return -ENOMEM;
+
+ cp->ctx_arr = kzalloc(blks * sizeof(struct cnic_ctx), GFP_KERNEL);
+ if (cp->ctx_arr == NULL)
+ return -ENOMEM;
+
+ cp->ctx_blks = blks;
+ cp->ctx_blk_size = ctx_blk_size;
+ if (BNX2X_CHIP_IS_E1H(cp->chip_id))
+ cp->ctx_align = 0;
+ else
+ cp->ctx_align = ctx_blk_size;
+
+ cp->cids_per_blk = ctx_blk_size / BNX2X_CONTEXT_MEM_SIZE;
+
+ for (i = 0; i < blks; i++) {
+ cp->ctx_arr[i].ctx =
+ pci_alloc_consistent(dev->pcidev, cp->ctx_blk_size,
+ &cp->ctx_arr[i].mapping);
+ if (cp->ctx_arr[i].ctx == NULL)
+ return -ENOMEM;
+
+ if (cp->ctx_align && cp->ctx_blk_size == ctx_blk_size) {
+ if (cp->ctx_arr[i].mapping & (cp->ctx_align - 1)) {
+ cnic_free_context(dev);
+ cp->ctx_blk_size += cp->ctx_align;
+ i = -1;
+ continue;
+ }
+ }
+ }
+ return 0;
+}
+
+static int cnic_alloc_bnx2x_resc(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int i, j, n, ret, pages;
+ struct cnic_dma *kwq_16_dma = &cp->kwq_16_data_info;
+
+ cp->iscsi_tbl = kzalloc(sizeof(struct cnic_iscsi) * MAX_ISCSI_TBL_SZ,
+ GFP_KERNEL);
+ if (!cp->iscsi_tbl)
+ goto error;
+
+ cp->ctx_tbl = kzalloc(sizeof(struct cnic_context) *
+ MAX_CNIC_L5_CONTEXT, GFP_KERNEL);
+ if (!cp->ctx_tbl)
+ goto error;
+
+ for (i = 0; i < MAX_ISCSI_TBL_SZ; i++) {
+ cp->ctx_tbl[i].proto.iscsi = &cp->iscsi_tbl[i];
+ cp->ctx_tbl[i].ulp_proto_id = CNIC_ULP_ISCSI;
+ }
+
+ pages = PAGE_ALIGN(MAX_CNIC_L5_CONTEXT * CNIC_KWQ16_DATA_SIZE) /
+ PAGE_SIZE;
+
+ ret = cnic_alloc_dma(dev, kwq_16_dma, pages, 0);
+ if (ret)
+ return -ENOMEM;
+
+ n = PAGE_SIZE / CNIC_KWQ16_DATA_SIZE;
+ for (i = 0, j = 0; i < MAX_ISCSI_TBL_SZ; i++) {
+ long off = CNIC_KWQ16_DATA_SIZE * (i % n);
+
+ cp->ctx_tbl[i].kwqe_data = kwq_16_dma->pg_arr[j] + off;
+ cp->ctx_tbl[i].kwqe_data_mapping = kwq_16_dma->pg_map_arr[j] +
+ off;
+
+ if ((i % n) == (n - 1))
+ j++;
+ }
+
+ ret = cnic_alloc_dma(dev, &cp->kcq_info, KCQ_PAGE_CNT, 0);
+ if (ret)
+ goto error;
+ cp->kcq = (struct kcqe **) cp->kcq_info.pg_arr;
+
+ for (i = 0; i < KCQ_PAGE_CNT; i++) {
+ struct bnx2x_bd_chain_next *next =
+ (struct bnx2x_bd_chain_next *)
+ &cp->kcq[i][MAX_KCQE_CNT];
+ int j = i + 1;
+
+ if (j >= KCQ_PAGE_CNT)
+ j = 0;
+ next->addr_hi = (u64) cp->kcq_info.pg_map_arr[j] >> 32;
+ next->addr_lo = cp->kcq_info.pg_map_arr[j] & 0xffffffff;
+ }
+
+ pages = PAGE_ALIGN(BNX2X_ISCSI_NUM_CONNECTIONS *
+ BNX2X_ISCSI_CONN_BUF_SIZE) / PAGE_SIZE;
+ ret = cnic_alloc_dma(dev, &cp->conn_buf_info, pages, 1);
+ if (ret)
+ goto error;
+
+ pages = PAGE_ALIGN(BNX2X_ISCSI_GLB_BUF_SIZE) / PAGE_SIZE;
+ ret = cnic_alloc_dma(dev, &cp->gbl_buf_info, pages, 0);
+ if (ret)
+ goto error;
+
+ ret = cnic_alloc_bnx2x_context(dev);
+ if (ret)
+ goto error;
+
+ cp->bnx2x_status_blk = cp->status_blk;
+ cp->bnx2x_def_status_blk = cp->ethdev->irq_arr[1].status_blk;
+
+ cp->l2_rx_ring_size = 15;
+
+ ret = cnic_alloc_l2_rings(dev, 4);
+ if (ret)
+ goto error;
+
+ ret = cnic_alloc_uio(dev);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ cnic_free_resc(dev);
+ return -ENOMEM;
+}
+
static inline u32 cnic_kwq_avail(struct cnic_local *cp)
{
return cp->max_kwq_idx -
@@ -939,6 +1155,880 @@ static int cnic_submit_bnx2_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
return 0;
}
+static void *cnic_get_kwqe_16_data(struct cnic_local *cp, u32 l5_cid,
+ union l5cm_specific_data *l5_data)
+{
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+ dma_addr_t map;
+
+ map = ctx->kwqe_data_mapping;
+ l5_data->phy_address.lo = (u64) map & 0xffffffff;
+ l5_data->phy_address.hi = (u64) map >> 32;
+ return ctx->kwqe_data;
+}
+
+static int cnic_submit_kwqe_16(struct cnic_dev *dev, u32 cmd, u32 cid,
+ u32 type, union l5cm_specific_data *l5_data)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct l5cm_spe kwqe;
+ struct kwqe_16 *kwq[1];
+ int ret;
+
+ kwqe.hdr.conn_and_cmd_data =
+ cpu_to_le32(((cmd << SPE_HDR_CMD_ID_SHIFT) |
+ BNX2X_HW_CID(cid, cp->func)));
+ kwqe.hdr.type = cpu_to_le16(type);
+ kwqe.hdr.reserved = 0;
+ kwqe.data.phy_address.lo = cpu_to_le32(l5_data->phy_address.lo);
+ kwqe.data.phy_address.hi = cpu_to_le32(l5_data->phy_address.hi);
+
+ kwq[0] = (struct kwqe_16 *) &kwqe;
+
+ spin_lock_bh(&cp->cnic_ulp_lock);
+ ret = cp->ethdev->drv_submit_kwqes_16(dev->netdev, kwq, 1);
+ spin_unlock_bh(&cp->cnic_ulp_lock);
+
+ if (ret == 1)
+ return 0;
+
+ return -EBUSY;
+}
+
+static void cnic_reply_bnx2x_kcqes(struct cnic_dev *dev, int ulp_type,
+ struct kcqe *cqes[], u32 num_cqes)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_ulp_ops *ulp_ops;
+
+ rcu_read_lock();
+ ulp_ops = rcu_dereference(cp->ulp_ops[ulp_type]);
+ if (likely(ulp_ops)) {
+ ulp_ops->indicate_kcqes(cp->ulp_handle[ulp_type],
+ cqes, num_cqes);
+ }
+ rcu_read_unlock();
+}
+
+static int cnic_bnx2x_iscsi_init1(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct iscsi_kwqe_init1 *req1 = (struct iscsi_kwqe_init1 *) kwqe;
+ int func = cp->func, pages;
+ int hq_bds;
+
+ cp->num_iscsi_tasks = req1->num_tasks_per_conn;
+ cp->num_ccells = req1->num_ccells_per_conn;
+ cp->task_array_size = BNX2X_ISCSI_TASK_CONTEXT_SIZE *
+ cp->num_iscsi_tasks;
+ cp->r2tq_size = cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS *
+ BNX2X_ISCSI_R2TQE_SIZE;
+ cp->hq_size = cp->num_ccells * BNX2X_ISCSI_HQ_BD_SIZE;
+ pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
+ hq_bds = pages * (PAGE_SIZE / BNX2X_ISCSI_HQ_BD_SIZE);
+ cp->num_cqs = req1->num_cqs;
+
+ if (!dev->max_iscsi_conn)
+ return 0;
+
+ /* init Tstorm RAM */
+ CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_RQ_SIZE_OFFSET(func),
+ req1->rq_num_wqes);
+ CNIC_WR16(dev, BAR_TSTRORM_INTMEM + TSTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ PAGE_SIZE);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ req1->num_tasks_per_conn);
+
+ /* init Ustorm RAM */
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_RQ_BUFFER_SIZE_OFFSET(func),
+ req1->rq_buffer_size);
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ PAGE_SIZE);
+ CNIC_WR8(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ req1->num_tasks_per_conn);
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_RQ_SIZE_OFFSET(func),
+ req1->rq_num_wqes);
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_CQ_SIZE_OFFSET(func),
+ req1->cq_num_wqes);
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM + USTORM_ISCSI_R2TQ_SIZE_OFFSET(func),
+ cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS);
+
+ /* init Xstorm RAM */
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ PAGE_SIZE);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ req1->num_tasks_per_conn);
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_HQ_SIZE_OFFSET(func),
+ hq_bds);
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_SQ_SIZE_OFFSET(func),
+ req1->num_tasks_per_conn);
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM + XSTORM_ISCSI_R2TQ_SIZE_OFFSET(func),
+ cp->num_iscsi_tasks * BNX2X_ISCSI_MAX_PENDING_R2TS);
+
+ /* init Cstorm RAM */
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_PAGE_SIZE_OFFSET(func),
+ PAGE_SIZE);
+ CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_PAGE_SIZE_LOG_OFFSET(func), PAGE_SHIFT);
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_NUM_OF_TASKS_OFFSET(func),
+ req1->num_tasks_per_conn);
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_CQ_SIZE_OFFSET(func),
+ req1->cq_num_wqes);
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM + CSTORM_ISCSI_HQ_SIZE_OFFSET(func),
+ hq_bds);
+
+ return 0;
+}
+
+static int cnic_bnx2x_iscsi_init2(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct iscsi_kwqe_init2 *req2 = (struct iscsi_kwqe_init2 *) kwqe;
+ struct cnic_local *cp = dev->cnic_priv;
+ int func = cp->func;
+ struct iscsi_kcqe kcqe;
+ struct kcqe *cqes[1];
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ if (!dev->max_iscsi_conn) {
+ kcqe.completion_status =
+ ISCSI_KCQE_COMPLETION_STATUS_ISCSI_NOT_SUPPORTED;
+ goto done;
+ }
+
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_ERROR_BITMAP_OFFSET(func), req2->error_bit_map[0]);
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_ERROR_BITMAP_OFFSET(func) + 4,
+ req2->error_bit_map[1]);
+
+ CNIC_WR16(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_CQ_SQN_SIZE_OFFSET(func), req2->max_cq_sqn);
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_ERROR_BITMAP_OFFSET(func), req2->error_bit_map[0]);
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_ERROR_BITMAP_OFFSET(func) + 4,
+ req2->error_bit_map[1]);
+
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_CQ_SQN_SIZE_OFFSET(func), req2->max_cq_sqn);
+
+ kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_SUCCESS;
+
+done:
+ kcqe.op_code = ISCSI_KCQE_OPCODE_INIT;
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1);
+
+ return 0;
+}
+
+static void cnic_free_bnx2x_conn_resc(struct cnic_dev *dev, u32 l5_cid)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+
+ if (ctx->ulp_proto_id == CNIC_ULP_ISCSI) {
+ struct cnic_iscsi *iscsi = ctx->proto.iscsi;
+
+ cnic_free_dma(dev, &iscsi->hq_info);
+ cnic_free_dma(dev, &iscsi->r2tq_info);
+ cnic_free_dma(dev, &iscsi->task_array_info);
+ }
+ cnic_free_id(&cp->cid_tbl, ctx->cid);
+ ctx->cid = 0;
+}
+
+static int cnic_alloc_bnx2x_conn_resc(struct cnic_dev *dev, u32 l5_cid)
+{
+ u32 cid;
+ int ret, pages;
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+ struct cnic_iscsi *iscsi = ctx->proto.iscsi;
+
+ cid = cnic_alloc_new_id(&cp->cid_tbl);
+ if (cid == -1) {
+ ret = -ENOMEM;
+ goto error;
+ }
+
+ ctx->cid = cid;
+ pages = PAGE_ALIGN(cp->task_array_size) / PAGE_SIZE;
+
+ ret = cnic_alloc_dma(dev, &iscsi->task_array_info, pages, 1);
+ if (ret)
+ goto error;
+
+ pages = PAGE_ALIGN(cp->r2tq_size) / PAGE_SIZE;
+ ret = cnic_alloc_dma(dev, &iscsi->r2tq_info, pages, 1);
+ if (ret)
+ goto error;
+
+ pages = PAGE_ALIGN(cp->hq_size) / PAGE_SIZE;
+ ret = cnic_alloc_dma(dev, &iscsi->hq_info, pages, 1);
+ if (ret)
+ goto error;
+
+ return 0;
+
+error:
+ cnic_free_bnx2x_conn_resc(dev, l5_cid);
+ return ret;
+}
+
+static void *cnic_get_bnx2x_ctx(struct cnic_dev *dev, u32 cid, int init,
+ struct regpair *ctx_addr)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ int blk = (cid - ethdev->starting_cid) / cp->cids_per_blk;
+ int off = (cid - ethdev->starting_cid) % cp->cids_per_blk;
+ unsigned long align_off = 0;
+ dma_addr_t ctx_map;
+ void *ctx;
+
+ if (cp->ctx_align) {
+ unsigned long mask = cp->ctx_align - 1;
+
+ if (cp->ctx_arr[blk].mapping & mask)
+ align_off = cp->ctx_align -
+ (cp->ctx_arr[blk].mapping & mask);
+ }
+ ctx_map = cp->ctx_arr[blk].mapping + align_off +
+ (off * BNX2X_CONTEXT_MEM_SIZE);
+ ctx = cp->ctx_arr[blk].ctx + align_off +
+ (off * BNX2X_CONTEXT_MEM_SIZE);
+ if (init)
+ memset(ctx, 0, BNX2X_CONTEXT_MEM_SIZE);
+
+ ctx_addr->lo = ctx_map & 0xffffffff;
+ ctx_addr->hi = (u64) ctx_map >> 32;
+ return ctx;
+}
+
+static int cnic_setup_bnx2x_ctx(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct iscsi_kwqe_conn_offload1 *req1 =
+ (struct iscsi_kwqe_conn_offload1 *) wqes[0];
+ struct iscsi_kwqe_conn_offload2 *req2 =
+ (struct iscsi_kwqe_conn_offload2 *) wqes[1];
+ struct iscsi_kwqe_conn_offload3 *req3;
+ struct cnic_context *ctx = &cp->ctx_tbl[req1->iscsi_conn_id];
+ struct cnic_iscsi *iscsi = ctx->proto.iscsi;
+ u32 cid = ctx->cid;
+ u32 hw_cid = BNX2X_HW_CID(cid, cp->func);
+ struct iscsi_context *ictx;
+ struct regpair context_addr;
+ int i, j, n = 2, n_max;
+
+ ctx->ctx_flags = 0;
+ if (!req2->num_additional_wqes)
+ return -EINVAL;
+
+ n_max = req2->num_additional_wqes + 2;
+
+ ictx = cnic_get_bnx2x_ctx(dev, cid, 1, &context_addr);
+ if (ictx == NULL)
+ return -ENOMEM;
+
+ req3 = (struct iscsi_kwqe_conn_offload3 *) wqes[n++];
+
+ ictx->xstorm_ag_context.hq_prod = 1;
+
+ ictx->xstorm_st_context.iscsi.first_burst_length =
+ ISCSI_DEF_FIRST_BURST_LEN;
+ ictx->xstorm_st_context.iscsi.max_send_pdu_length =
+ ISCSI_DEF_MAX_RECV_SEG_LEN;
+ ictx->xstorm_st_context.iscsi.sq_pbl_base.lo =
+ req1->sq_page_table_addr_lo;
+ ictx->xstorm_st_context.iscsi.sq_pbl_base.hi =
+ req1->sq_page_table_addr_hi;
+ ictx->xstorm_st_context.iscsi.sq_curr_pbe.lo = req2->sq_first_pte.hi;
+ ictx->xstorm_st_context.iscsi.sq_curr_pbe.hi = req2->sq_first_pte.lo;
+ ictx->xstorm_st_context.iscsi.hq_pbl_base.lo =
+ iscsi->hq_info.pgtbl_map & 0xffffffff;
+ ictx->xstorm_st_context.iscsi.hq_pbl_base.hi =
+ (u64) iscsi->hq_info.pgtbl_map >> 32;
+ ictx->xstorm_st_context.iscsi.hq_curr_pbe_base.lo =
+ iscsi->hq_info.pgtbl[0];
+ ictx->xstorm_st_context.iscsi.hq_curr_pbe_base.hi =
+ iscsi->hq_info.pgtbl[1];
+ ictx->xstorm_st_context.iscsi.r2tq_pbl_base.lo =
+ iscsi->r2tq_info.pgtbl_map & 0xffffffff;
+ ictx->xstorm_st_context.iscsi.r2tq_pbl_base.hi =
+ (u64) iscsi->r2tq_info.pgtbl_map >> 32;
+ ictx->xstorm_st_context.iscsi.r2tq_curr_pbe_base.lo =
+ iscsi->r2tq_info.pgtbl[0];
+ ictx->xstorm_st_context.iscsi.r2tq_curr_pbe_base.hi =
+ iscsi->r2tq_info.pgtbl[1];
+ ictx->xstorm_st_context.iscsi.task_pbl_base.lo =
+ iscsi->task_array_info.pgtbl_map & 0xffffffff;
+ ictx->xstorm_st_context.iscsi.task_pbl_base.hi =
+ (u64) iscsi->task_array_info.pgtbl_map >> 32;
+ ictx->xstorm_st_context.iscsi.task_pbl_cache_idx =
+ BNX2X_ISCSI_PBL_NOT_CACHED;
+ ictx->xstorm_st_context.iscsi.flags.flags |=
+ XSTORM_ISCSI_CONTEXT_FLAGS_B_IMMEDIATE_DATA;
+ ictx->xstorm_st_context.iscsi.flags.flags |=
+ XSTORM_ISCSI_CONTEXT_FLAGS_B_INITIAL_R2T;
+
+ ictx->tstorm_st_context.iscsi.hdr_bytes_2_fetch = ISCSI_HEADER_SIZE;
+ /* TSTORM requires the base address of RQ DB & not PTE */
+ ictx->tstorm_st_context.iscsi.rq_db_phy_addr.lo =
+ req2->rq_page_table_addr_lo & PAGE_MASK;
+ ictx->tstorm_st_context.iscsi.rq_db_phy_addr.hi =
+ req2->rq_page_table_addr_hi;
+ ictx->tstorm_st_context.iscsi.iscsi_conn_id = req1->iscsi_conn_id;
+ ictx->tstorm_st_context.tcp.cwnd = 0x5A8;
+ ictx->tstorm_st_context.tcp.flags2 |=
+ TSTORM_TCP_ST_CONTEXT_SECTION_DA_EN;
+
+ ictx->timers_context.flags |= ISCSI_TIMERS_BLOCK_CONTEXT_CONN_VALID_FLG;
+
+ ictx->ustorm_st_context.ring.rq.pbl_base.lo =
+ req2->rq_page_table_addr_lo & 0xffffffff;
+ ictx->ustorm_st_context.ring.rq.pbl_base.hi =
+ (u64) req2->rq_page_table_addr_hi >> 32;
+ ictx->ustorm_st_context.ring.rq.curr_pbe.lo = req3->qp_first_pte[0].hi;
+ ictx->ustorm_st_context.ring.rq.curr_pbe.hi = req3->qp_first_pte[0].lo;
+ ictx->ustorm_st_context.ring.r2tq.pbl_base.lo =
+ iscsi->r2tq_info.pgtbl_map & 0xffffffff;
+ ictx->ustorm_st_context.ring.r2tq.pbl_base.hi =
+ (u64) iscsi->r2tq_info.pgtbl_map >> 32;
+ ictx->ustorm_st_context.ring.r2tq.curr_pbe.lo =
+ iscsi->r2tq_info.pgtbl[0];
+ ictx->ustorm_st_context.ring.r2tq.curr_pbe.hi =
+ iscsi->r2tq_info.pgtbl[1];
+ ictx->ustorm_st_context.ring.cq_pbl_base.lo =
+ req1->cq_page_table_addr_lo;
+ ictx->ustorm_st_context.ring.cq_pbl_base.hi =
+ req1->cq_page_table_addr_hi;
+ ictx->ustorm_st_context.ring.cq[0].cq_sn = ISCSI_INITIAL_SN;
+ ictx->ustorm_st_context.ring.cq[0].curr_pbe.lo = req2->cq_first_pte.hi;
+ ictx->ustorm_st_context.ring.cq[0].curr_pbe.hi = req2->cq_first_pte.lo;
+ ictx->ustorm_st_context.task_pbe_cache_index =
+ BNX2X_ISCSI_PBL_NOT_CACHED;
+ ictx->ustorm_st_context.task_pdu_cache_index =
+ BNX2X_ISCSI_PDU_HEADER_NOT_CACHED;
+
+ for (i = 1, j = 1; i < cp->num_cqs; i++, j++) {
+ if (j == 3) {
+ if (n >= n_max)
+ break;
+ req3 = (struct iscsi_kwqe_conn_offload3 *) wqes[n++];
+ j = 0;
+ }
+ ictx->ustorm_st_context.ring.cq[i].cq_sn = ISCSI_INITIAL_SN;
+ ictx->ustorm_st_context.ring.cq[i].curr_pbe.lo =
+ req3->qp_first_pte[j].hi;
+ ictx->ustorm_st_context.ring.cq[i].curr_pbe.hi =
+ req3->qp_first_pte[j].lo;
+ }
+
+ ictx->ustorm_st_context.task_pbl_base.lo =
+ iscsi->task_array_info.pgtbl_map & 0xffffffff;
+ ictx->ustorm_st_context.task_pbl_base.hi =
+ (u64) iscsi->task_array_info.pgtbl_map >> 32;
+ ictx->ustorm_st_context.tce_phy_addr.lo =
+ iscsi->task_array_info.pgtbl[0];
+ ictx->ustorm_st_context.tce_phy_addr.hi =
+ iscsi->task_array_info.pgtbl[1];
+ ictx->ustorm_st_context.iscsi_conn_id = req1->iscsi_conn_id;
+ ictx->ustorm_st_context.num_cqs = cp->num_cqs;
+ ictx->ustorm_st_context.negotiated_rx |= ISCSI_DEF_MAX_RECV_SEG_LEN;
+ ictx->ustorm_st_context.negotiated_rx_and_flags |=
+ ISCSI_DEF_MAX_BURST_LEN;
+ ictx->ustorm_st_context.negotiated_rx |=
+ ISCSI_DEFAULT_MAX_OUTSTANDING_R2T <<
+ USTORM_ISCSI_ST_CONTEXT_MAX_OUTSTANDING_R2TS_SHIFT;
+
+ ictx->cstorm_st_context.hq_pbl_base.lo =
+ iscsi->hq_info.pgtbl_map & 0xffffffff;
+ ictx->cstorm_st_context.hq_pbl_base.hi =
+ (u64) iscsi->hq_info.pgtbl_map >> 32;
+ ictx->cstorm_st_context.hq_curr_pbe.lo = iscsi->hq_info.pgtbl[0];
+ ictx->cstorm_st_context.hq_curr_pbe.hi = iscsi->hq_info.pgtbl[1];
+ ictx->cstorm_st_context.task_pbl_base.lo =
+ iscsi->task_array_info.pgtbl_map & 0xffffffff;
+ ictx->cstorm_st_context.task_pbl_base.hi =
+ (u64) iscsi->task_array_info.pgtbl_map >> 32;
+ /* CSTORM and USTORM initialization is different, CSTORM requires
+ * CQ DB base & not PTE addr */
+ ictx->cstorm_st_context.cq_db_base.lo =
+ req1->cq_page_table_addr_lo & PAGE_MASK;
+ ictx->cstorm_st_context.cq_db_base.hi = req1->cq_page_table_addr_hi;
+ ictx->cstorm_st_context.iscsi_conn_id = req1->iscsi_conn_id;
+ ictx->cstorm_st_context.cq_proc_en_bit_map = (1 << cp->num_cqs) - 1;
+ for (i = 0; i < cp->num_cqs; i++) {
+ ictx->cstorm_st_context.cq_c_prod_sqn_arr.sqn[i] =
+ ISCSI_INITIAL_SN;
+ ictx->cstorm_st_context.cq_c_sqn_2_notify_arr.sqn[i] =
+ ISCSI_INITIAL_SN;
+ }
+
+ ictx->xstorm_ag_context.cdu_reserved =
+ CDU_RSRVD_VALUE_TYPE_A(hw_cid, CDU_REGION_NUMBER_XCM_AG,
+ ISCSI_CONNECTION_TYPE);
+ ictx->ustorm_ag_context.cdu_usage =
+ CDU_RSRVD_VALUE_TYPE_A(hw_cid, CDU_REGION_NUMBER_UCM_AG,
+ ISCSI_CONNECTION_TYPE);
+ return 0;
+
+}
+
+static int cnic_bnx2x_iscsi_ofld1(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num, int *work)
+{
+ struct iscsi_kwqe_conn_offload1 *req1;
+ struct iscsi_kwqe_conn_offload2 *req2;
+ struct cnic_local *cp = dev->cnic_priv;
+ struct iscsi_kcqe kcqe;
+ struct kcqe *cqes[1];
+ u32 l5_cid;
+ int ret;
+
+ if (num < 2) {
+ *work = num;
+ return -EINVAL;
+ }
+
+ req1 = (struct iscsi_kwqe_conn_offload1 *) wqes[0];
+ req2 = (struct iscsi_kwqe_conn_offload2 *) wqes[1];
+ if ((num - 2) < req2->num_additional_wqes) {
+ *work = num;
+ return -EINVAL;
+ }
+ *work = 2 + req2->num_additional_wqes;;
+
+ l5_cid = req1->iscsi_conn_id;
+ if (l5_cid >= MAX_ISCSI_TBL_SZ)
+ return -EINVAL;
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.op_code = ISCSI_KCQE_OPCODE_OFFLOAD_CONN;
+ kcqe.iscsi_conn_id = l5_cid;
+ kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_CTX_ALLOC_FAILURE;
+
+ if (atomic_inc_return(&cp->iscsi_conn) > dev->max_iscsi_conn) {
+ atomic_dec(&cp->iscsi_conn);
+ ret = 0;
+ goto done;
+ }
+ ret = cnic_alloc_bnx2x_conn_resc(dev, l5_cid);
+ if (ret) {
+ atomic_dec(&cp->iscsi_conn);
+ ret = 0;
+ goto done;
+ }
+ ret = cnic_setup_bnx2x_ctx(dev, wqes, num);
+ if (ret < 0) {
+ cnic_free_bnx2x_conn_resc(dev, l5_cid);
+ atomic_dec(&cp->iscsi_conn);
+ goto done;
+ }
+
+ kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_SUCCESS;
+ kcqe.iscsi_conn_context_id = BNX2X_HW_CID(cp->ctx_tbl[l5_cid].cid,
+ cp->func);
+
+done:
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1);
+ return ret;
+}
+
+
+static int cnic_bnx2x_iscsi_update(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct iscsi_kwqe_conn_update *req =
+ (struct iscsi_kwqe_conn_update *) kwqe;
+ void *data;
+ union l5cm_specific_data l5_data;
+ u32 l5_cid, cid = BNX2X_SW_CID(req->context_id);
+ int ret;
+
+ if (cnic_get_l5_cid(cp, cid, &l5_cid) != 0)
+ return -EINVAL;
+
+ data = cnic_get_kwqe_16_data(cp, l5_cid, &l5_data);
+ if (!data)
+ return -ENOMEM;
+
+ memcpy(data, kwqe, sizeof(struct kwqe));
+
+ ret = cnic_submit_kwqe_16(dev, ISCSI_RAMROD_CMD_ID_UPDATE_CONN,
+ req->context_id, ISCSI_CONNECTION_TYPE, &l5_data);
+ return ret;
+}
+
+static int cnic_bnx2x_iscsi_destroy(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct iscsi_kwqe_conn_destroy *req =
+ (struct iscsi_kwqe_conn_destroy *) kwqe;
+ union l5cm_specific_data l5_data;
+ u32 l5_cid = req->reserved0;
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+ int ret = 0;
+ struct iscsi_kcqe kcqe;
+ struct kcqe *cqes[1];
+
+ if (!(ctx->ctx_flags & CTX_FL_OFFLD_START))
+ goto skip_cfc_delete;
+
+ while (!time_after(jiffies, ctx->timestamp + (2 * HZ)))
+ msleep(250);
+
+ init_waitqueue_head(&ctx->waitq);
+ ctx->wait_cond = 0;
+ memset(&l5_data, 0, sizeof(l5_data));
+ ret = cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CFC_DEL,
+ req->context_id,
+ ETH_CONNECTION_TYPE |
+ (1 << SPE_HDR_COMMON_RAMROD_SHIFT),
+ &l5_data);
+ if (ret == 0)
+ wait_event(ctx->waitq, ctx->wait_cond);
+
+skip_cfc_delete:
+ cnic_free_bnx2x_conn_resc(dev, l5_cid);
+
+ atomic_dec(&cp->iscsi_conn);
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.op_code = ISCSI_KCQE_OPCODE_DESTROY_CONN;
+ kcqe.iscsi_conn_id = l5_cid;
+ kcqe.completion_status = ISCSI_KCQE_COMPLETION_STATUS_SUCCESS;
+ kcqe.iscsi_conn_context_id = req->context_id;
+
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_ISCSI, cqes, 1);
+
+ return ret;
+}
+
+static void cnic_init_storm_conn_bufs(struct cnic_dev *dev,
+ struct l4_kwq_connect_req1 *kwqe1,
+ struct l4_kwq_connect_req3 *kwqe3,
+ struct l5cm_active_conn_buffer *conn_buf)
+{
+ struct l5cm_conn_addr_params *conn_addr = &conn_buf->conn_addr_buf;
+ struct l5cm_xstorm_conn_buffer *xstorm_buf =
+ &conn_buf->xstorm_conn_buffer;
+ struct l5cm_tstorm_conn_buffer *tstorm_buf =
+ &conn_buf->tstorm_conn_buffer;
+ struct regpair context_addr;
+ u32 cid = BNX2X_SW_CID(kwqe1->cid);
+ struct in6_addr src_ip, dst_ip;
+ int i;
+ u32 *addrp;
+
+ addrp = (u32 *) &conn_addr->local_ip_addr;
+ for (i = 0; i < 4; i++, addrp++)
+ src_ip.in6_u.u6_addr32[i] = cpu_to_be32(*addrp);
+
+ addrp = (u32 *) &conn_addr->remote_ip_addr;
+ for (i = 0; i < 4; i++, addrp++)
+ dst_ip.in6_u.u6_addr32[i] = cpu_to_be32(*addrp);
+
+ cnic_get_bnx2x_ctx(dev, cid, 0, &context_addr);
+
+ xstorm_buf->context_addr.hi = context_addr.hi;
+ xstorm_buf->context_addr.lo = context_addr.lo;
+ xstorm_buf->mss = 0xffff;
+ xstorm_buf->rcv_buf = kwqe3->rcv_buf;
+ if (kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_NAGLE_ENABLE)
+ xstorm_buf->params |= L5CM_XSTORM_CONN_BUFFER_NAGLE_ENABLE;
+ xstorm_buf->pseudo_header_checksum =
+ swab16(~csum_ipv6_magic(&src_ip, &dst_ip, 0, IPPROTO_TCP, 0));
+
+ if (!(kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_NO_DELAY_ACK))
+ tstorm_buf->params |=
+ L5CM_TSTORM_CONN_BUFFER_DELAYED_ACK_ENABLE;
+ if (kwqe3->ka_timeout) {
+ tstorm_buf->ka_enable = 1;
+ tstorm_buf->ka_timeout = kwqe3->ka_timeout;
+ tstorm_buf->ka_interval = kwqe3->ka_interval;
+ tstorm_buf->ka_max_probe_count = kwqe3->ka_max_probe_count;
+ }
+ tstorm_buf->rcv_buf = kwqe3->rcv_buf;
+ tstorm_buf->snd_buf = kwqe3->snd_buf;
+ tstorm_buf->max_rt_time = 0xffffffff;
+}
+
+static void cnic_init_bnx2x_mac(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int func = CNIC_FUNC(cp);
+ u8 *mac = dev->mac_addr;
+
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR0_OFFSET(func), mac[0]);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR1_OFFSET(func), mac[1]);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR2_OFFSET(func), mac[2]);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR3_OFFSET(func), mac[3]);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR4_OFFSET(func), mac[4]);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_MAC_ADDR5_OFFSET(func), mac[5]);
+
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(func), mac[5]);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_LSB_LOCAL_MAC_ADDR_OFFSET(func) + 1,
+ mac[4]);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func), mac[3]);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 1,
+ mac[2]);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 2,
+ mac[1]);
+ CNIC_WR8(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_MSB_LOCAL_MAC_ADDR_OFFSET(func) + 3,
+ mac[0]);
+}
+
+static void cnic_bnx2x_set_tcp_timestamp(struct cnic_dev *dev, int tcp_ts)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u8 xstorm_flags = XSTORM_L5CM_TCP_FLAGS_WND_SCL_EN;
+ u16 tstorm_flags = 0;
+
+ if (tcp_ts) {
+ xstorm_flags |= XSTORM_L5CM_TCP_FLAGS_TS_ENABLED;
+ tstorm_flags |= TSTORM_L5CM_TCP_FLAGS_TS_ENABLED;
+ }
+
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->func), xstorm_flags);
+
+ CNIC_WR16(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_TCP_VARS_FLAGS_OFFSET(cp->func), tstorm_flags);
+}
+
+static int cnic_bnx2x_connect(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num, int *work)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct l4_kwq_connect_req1 *kwqe1 =
+ (struct l4_kwq_connect_req1 *) wqes[0];
+ struct l4_kwq_connect_req3 *kwqe3;
+ struct l5cm_active_conn_buffer *conn_buf;
+ struct l5cm_conn_addr_params *conn_addr;
+ union l5cm_specific_data l5_data;
+ u32 l5_cid = kwqe1->pg_cid;
+ struct cnic_sock *csk = &cp->csk_tbl[l5_cid];
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+ int ret;
+
+ if (num < 2) {
+ *work = num;
+ return -EINVAL;
+ }
+
+ if (kwqe1->conn_flags & L4_KWQ_CONNECT_REQ1_IP_V6)
+ *work = 3;
+ else
+ *work = 2;
+
+ if (num < *work) {
+ *work = num;
+ return -EINVAL;
+ }
+
+ if (sizeof(*conn_buf) > CNIC_KWQ16_DATA_SIZE) {
+ printk(KERN_ERR PFX "%s: conn_buf size too big\n",
+ dev->netdev->name);
+ return -ENOMEM;
+ }
+ conn_buf = cnic_get_kwqe_16_data(cp, l5_cid, &l5_data);
+ if (!conn_buf)
+ return -ENOMEM;
+
+ memset(conn_buf, 0, sizeof(*conn_buf));
+
+ conn_addr = &conn_buf->conn_addr_buf;
+ conn_addr->remote_addr_0 = csk->ha[0];
+ conn_addr->remote_addr_1 = csk->ha[1];
+ conn_addr->remote_addr_2 = csk->ha[2];
+ conn_addr->remote_addr_3 = csk->ha[3];
+ conn_addr->remote_addr_4 = csk->ha[4];
+ conn_addr->remote_addr_5 = csk->ha[5];
+
+ if (kwqe1->conn_flags & L4_KWQ_CONNECT_REQ1_IP_V6) {
+ struct l4_kwq_connect_req2 *kwqe2 =
+ (struct l4_kwq_connect_req2 *) wqes[1];
+
+ conn_addr->local_ip_addr.ip_addr_hi_hi = kwqe2->src_ip_v6_4;
+ conn_addr->local_ip_addr.ip_addr_hi_lo = kwqe2->src_ip_v6_3;
+ conn_addr->local_ip_addr.ip_addr_lo_hi = kwqe2->src_ip_v6_2;
+
+ conn_addr->remote_ip_addr.ip_addr_hi_hi = kwqe2->dst_ip_v6_4;
+ conn_addr->remote_ip_addr.ip_addr_hi_lo = kwqe2->dst_ip_v6_3;
+ conn_addr->remote_ip_addr.ip_addr_lo_hi = kwqe2->dst_ip_v6_2;
+ conn_addr->params |= L5CM_CONN_ADDR_PARAMS_IP_VERSION;
+ }
+ kwqe3 = (struct l4_kwq_connect_req3 *) wqes[*work - 1];
+
+ conn_addr->local_ip_addr.ip_addr_lo_lo = kwqe1->src_ip;
+ conn_addr->remote_ip_addr.ip_addr_lo_lo = kwqe1->dst_ip;
+ conn_addr->local_tcp_port = kwqe1->src_port;
+ conn_addr->remote_tcp_port = kwqe1->dst_port;
+
+ conn_addr->pmtu = kwqe3->pmtu;
+ cnic_init_storm_conn_bufs(dev, kwqe1, kwqe3, conn_buf);
+
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_VLAN_OFFSET(cp->func), csk->vlan_id);
+
+ cnic_bnx2x_set_tcp_timestamp(dev,
+ kwqe1->tcp_flags & L4_KWQ_CONNECT_REQ1_TIME_STAMP);
+
+ ret = cnic_submit_kwqe_16(dev, L5CM_RAMROD_CMD_ID_TCP_CONNECT,
+ kwqe1->cid, ISCSI_CONNECTION_TYPE, &l5_data);
+ if (!ret)
+ ctx->ctx_flags |= CTX_FL_OFFLD_START;
+
+ return ret;
+}
+
+static int cnic_bnx2x_close(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct l4_kwq_close_req *req = (struct l4_kwq_close_req *) kwqe;
+ union l5cm_specific_data l5_data;
+ int ret;
+
+ memset(&l5_data, 0, sizeof(l5_data));
+ ret = cnic_submit_kwqe_16(dev, L5CM_RAMROD_CMD_ID_CLOSE,
+ req->cid, ISCSI_CONNECTION_TYPE, &l5_data);
+ return ret;
+}
+
+static int cnic_bnx2x_reset(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct l4_kwq_reset_req *req = (struct l4_kwq_reset_req *) kwqe;
+ union l5cm_specific_data l5_data;
+ int ret;
+
+ memset(&l5_data, 0, sizeof(l5_data));
+ ret = cnic_submit_kwqe_16(dev, L5CM_RAMROD_CMD_ID_ABORT,
+ req->cid, ISCSI_CONNECTION_TYPE, &l5_data);
+ return ret;
+}
+static int cnic_bnx2x_offload_pg(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct l4_kwq_offload_pg *req = (struct l4_kwq_offload_pg *) kwqe;
+ struct l4_kcq kcqe;
+ struct kcqe *cqes[1];
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.pg_host_opaque = req->host_opaque;
+ kcqe.pg_cid = req->host_opaque;
+ kcqe.op_code = L4_KCQE_OPCODE_VALUE_OFFLOAD_PG;
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_L4, cqes, 1);
+ return 0;
+}
+
+static int cnic_bnx2x_update_pg(struct cnic_dev *dev, struct kwqe *kwqe)
+{
+ struct l4_kwq_update_pg *req = (struct l4_kwq_update_pg *) kwqe;
+ struct l4_kcq kcqe;
+ struct kcqe *cqes[1];
+
+ memset(&kcqe, 0, sizeof(kcqe));
+ kcqe.pg_host_opaque = req->pg_host_opaque;
+ kcqe.pg_cid = req->pg_cid;
+ kcqe.op_code = L4_KCQE_OPCODE_VALUE_UPDATE_PG;
+ cqes[0] = (struct kcqe *) &kcqe;
+ cnic_reply_bnx2x_kcqes(dev, CNIC_ULP_L4, cqes, 1);
+ return 0;
+}
+
+static int cnic_submit_bnx2x_kwqes(struct cnic_dev *dev, struct kwqe *wqes[],
+ u32 num_wqes)
+{
+ int i, work, ret;
+ u32 opcode;
+ struct kwqe *kwqe;
+
+ if (!test_bit(CNIC_F_CNIC_UP, &dev->flags))
+ return -EAGAIN; /* bnx2 is down */
+
+ for (i = 0; i < num_wqes; ) {
+ kwqe = wqes[i];
+ opcode = KWQE_OPCODE(kwqe->kwqe_op_flag);
+ work = 1;
+
+ switch (opcode) {
+ case ISCSI_KWQE_OPCODE_INIT1:
+ ret = cnic_bnx2x_iscsi_init1(dev, kwqe);
+ break;
+ case ISCSI_KWQE_OPCODE_INIT2:
+ ret = cnic_bnx2x_iscsi_init2(dev, kwqe);
+ break;
+ case ISCSI_KWQE_OPCODE_OFFLOAD_CONN1:
+ ret = cnic_bnx2x_iscsi_ofld1(dev, &wqes[i],
+ num_wqes - i, &work);
+ break;
+ case ISCSI_KWQE_OPCODE_UPDATE_CONN:
+ ret = cnic_bnx2x_iscsi_update(dev, kwqe);
+ break;
+ case ISCSI_KWQE_OPCODE_DESTROY_CONN:
+ ret = cnic_bnx2x_iscsi_destroy(dev, kwqe);
+ break;
+ case L4_KWQE_OPCODE_VALUE_CONNECT1:
+ ret = cnic_bnx2x_connect(dev, &wqes[i], num_wqes - i,
+ &work);
+ break;
+ case L4_KWQE_OPCODE_VALUE_CLOSE:
+ ret = cnic_bnx2x_close(dev, kwqe);
+ break;
+ case L4_KWQE_OPCODE_VALUE_RESET:
+ ret = cnic_bnx2x_reset(dev, kwqe);
+ break;
+ case L4_KWQE_OPCODE_VALUE_OFFLOAD_PG:
+ ret = cnic_bnx2x_offload_pg(dev, kwqe);
+ break;
+ case L4_KWQE_OPCODE_VALUE_UPDATE_PG:
+ ret = cnic_bnx2x_update_pg(dev, kwqe);
+ break;
+ case L4_KWQE_OPCODE_VALUE_UPLOAD_PG:
+ ret = 0;
+ break;
+ default:
+ ret = 0;
+ printk(KERN_ERR PFX "%s: Unknown type of KWQE(0x%x)\n",
+ dev->netdev->name, opcode);
+ break;
+ }
+ if (ret < 0)
+ printk(KERN_ERR PFX "%s: KWQE(0x%x) failed\n",
+ dev->netdev->name, opcode);
+ i += work;
+ }
+ return 0;
+}
+
static void service_kcqes(struct cnic_dev *dev, int num_cqes)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -1005,6 +2095,22 @@ static u16 cnic_bnx2_hw_idx(u16 idx)
return idx;
}
+static u16 cnic_bnx2x_next_idx(u16 idx)
+{
+ idx++;
+ if ((idx & MAX_KCQE_CNT) == MAX_KCQE_CNT)
+ idx++;
+
+ return idx;
+}
+
+static u16 cnic_bnx2x_hw_idx(u16 idx)
+{
+ if ((idx & MAX_KCQE_CNT) == MAX_KCQE_CNT)
+ idx++;
+ return idx;
+}
+
static int cnic_get_kcqes(struct cnic_dev *dev, u16 hw_prod, u16 *sw_prod)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -1038,6 +2144,7 @@ static void cnic_chk_pkt_rings(struct cnic_local *cp)
if (cp->tx_cons != tx_cons || cp->rx_cons != rx_cons) {
cp->tx_cons = tx_cons;
cp->rx_cons = rx_cons;
+
uio_event_notify(cp->cnic_uinfo);
}
}
@@ -1143,6 +2250,91 @@ static irqreturn_t cnic_irq(int irq, void *dev_instance)
return IRQ_HANDLED;
}
+static inline void cnic_ack_bnx2x_int(struct cnic_dev *dev, u8 id, u8 storm,
+ u16 index, u8 op, u8 update)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 hc_addr = (HC_REG_COMMAND_REG + CNIC_PORT(cp) * 32 +
+ COMMAND_REG_INT_ACK);
+ struct igu_ack_register igu_ack;
+
+ igu_ack.status_block_index = index;
+ igu_ack.sb_id_and_flags =
+ ((id << IGU_ACK_REGISTER_STATUS_BLOCK_ID_SHIFT) |
+ (storm << IGU_ACK_REGISTER_STORM_ID_SHIFT) |
+ (update << IGU_ACK_REGISTER_UPDATE_INDEX_SHIFT) |
+ (op << IGU_ACK_REGISTER_INTERRUPT_MODE_SHIFT));
+
+ CNIC_WR(dev, hc_addr, (*(u32 *)&igu_ack));
+}
+
+static void cnic_ack_bnx2x_msix(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+
+ cnic_ack_bnx2x_int(dev, cp->status_blk_num, CSTORM_ID, 0,
+ IGU_INT_DISABLE, 0);
+}
+
+static void cnic_service_bnx2x_bh(unsigned long data)
+{
+ struct cnic_dev *dev = (struct cnic_dev *) data;
+ struct cnic_local *cp = dev->cnic_priv;
+ u16 hw_prod, sw_prod;
+ struct cstorm_status_block_c *sblk =
+ &cp->bnx2x_status_blk->c_status_block;
+ u32 status_idx = sblk->status_block_index;
+ int kcqe_cnt;
+
+ if (unlikely(!test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+ return;
+
+ hw_prod = sblk->index_values[HC_INDEX_C_ISCSI_EQ_CONS];
+ hw_prod = cp->hw_idx(hw_prod);
+ sw_prod = cp->kcq_prod_idx;
+ while (sw_prod != hw_prod) {
+ kcqe_cnt = cnic_get_kcqes(dev, hw_prod, &sw_prod);
+ if (kcqe_cnt == 0)
+ goto done;
+
+ service_kcqes(dev, kcqe_cnt);
+
+ /* Tell compiler that sblk fields can change. */
+ barrier();
+ if (status_idx == sblk->status_block_index)
+ break;
+
+ status_idx = sblk->status_block_index;
+ hw_prod = sblk->index_values[HC_INDEX_C_ISCSI_EQ_CONS];
+ hw_prod = cp->hw_idx(hw_prod);
+ }
+
+done:
+ CNIC_WR16(dev, cp->kcq_io_addr, sw_prod + MAX_KCQ_IDX);
+ cnic_ack_bnx2x_int(dev, cp->status_blk_num, CSTORM_ID,
+ status_idx, IGU_INT_ENABLE, 1);
+
+ cp->kcq_prod_idx = sw_prod;
+ return;
+}
+
+static int cnic_service_bnx2x(void *data, void *status_blk)
+{
+ struct cnic_dev *dev = data;
+ struct cnic_local *cp = dev->cnic_priv;
+ u16 prod = cp->kcq_prod_idx & MAX_KCQ_IDX;
+
+ prefetch(cp->status_blk);
+ prefetch(&cp->kcq[KCQ_PG(prod)][KCQ_IDX(prod)]);
+
+ if (likely(test_bit(CNIC_F_CNIC_UP, &dev->flags)))
+ tasklet_schedule(&cp->cnic_irq_task);
+
+ cnic_chk_pkt_rings(cp);
+
+ return 0;
+}
+
static void cnic_ulp_stop(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -1215,6 +2407,19 @@ static int cnic_ctl(void *data, struct cnic_ctl_info *info)
cnic_put(dev);
break;
+ case CNIC_CTL_COMPLETION_CMD: {
+ u32 cid = BNX2X_SW_CID(info->data.comp.cid);
+ u32 l5_cid;
+ struct cnic_local *cp = dev->cnic_priv;
+
+ if (cnic_get_l5_cid(cp, cid, &l5_cid) == 0) {
+ struct cnic_context *ctx = &cp->ctx_tbl[l5_cid];
+
+ ctx->wait_cond = 1;
+ wake_up(&ctx->waitq);
+ }
+ break;
+ }
default:
return -EINVAL;
}
@@ -1890,6 +3095,8 @@ static void cnic_cm_process_kcqe(struct cnic_dev *dev, struct kcqe *kcqe)
/* fall through */
case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
case L4_KCQE_OPCODE_VALUE_RESET_COMP:
+ case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
+ case L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD:
cp->close_conn(csk, opcode);
break;
@@ -1975,6 +3182,76 @@ static int cnic_cm_init_bnx2_hw(struct cnic_dev *dev)
return 0;
}
+static void cnic_close_bnx2x_conn(struct cnic_sock *csk, u32 opcode)
+{
+ struct cnic_dev *dev = csk->dev;
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_context *ctx = &cp->ctx_tbl[csk->l5_cid];
+ union l5cm_specific_data l5_data;
+ u32 cmd = 0;
+ int close_complete = 0;
+
+ switch (opcode) {
+ case L4_KCQE_OPCODE_VALUE_RESET_RECEIVED:
+ case L4_KCQE_OPCODE_VALUE_CLOSE_COMP:
+ case L4_KCQE_OPCODE_VALUE_RESET_COMP:
+ if (cnic_ready_to_close(csk, opcode))
+ cmd = L5CM_RAMROD_CMD_ID_SEARCHER_DELETE;
+ break;
+ case L5CM_RAMROD_CMD_ID_SEARCHER_DELETE:
+ cmd = L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD;
+ break;
+ case L5CM_RAMROD_CMD_ID_TERMINATE_OFFLOAD:
+ close_complete = 1;
+ break;
+ }
+ if (cmd) {
+ memset(&l5_data, 0, sizeof(l5_data));
+
+ cnic_submit_kwqe_16(dev, cmd, csk->cid, ISCSI_CONNECTION_TYPE,
+ &l5_data);
+ } else if (close_complete) {
+ ctx->timestamp = jiffies;
+ cnic_close_conn(csk);
+ cnic_cm_upcall(cp, csk, csk->state);
+ }
+}
+
+static void cnic_cm_stop_bnx2x_hw(struct cnic_dev *dev)
+{
+}
+
+static int cnic_cm_init_bnx2x_hw(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int func = CNIC_FUNC(cp);
+
+ cnic_init_bnx2x_mac(dev);
+ cnic_bnx2x_set_tcp_timestamp(dev, 1);
+
+ CNIC_WR16(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_LOCAL_VLAN_OFFSET(func), 0);
+
+ CNIC_WR(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_ENABLED_OFFSET(func), 1);
+ CNIC_WR(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_TCP_GLOBAL_DEL_ACK_COUNTER_MAX_COUNT_OFFSET(func),
+ DEF_MAX_DA_COUNT);
+
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_TCP_VARS_TTL_OFFSET(func), DEF_TTL);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_TCP_VARS_TOS_OFFSET(func), DEF_TOS);
+ CNIC_WR8(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_ISCSI_TCP_VARS_ADV_WND_SCL_OFFSET(func), 2);
+ CNIC_WR(dev, BAR_XSTRORM_INTMEM +
+ XSTORM_TCP_TX_SWS_TIMER_VAL_OFFSET(func), DEF_SWS_TIMER);
+
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM + TSTORM_TCP_MAX_CWND_OFFSET(func),
+ DEF_MAX_CWND);
+ return 0;
+}
+
static int cnic_cm_open(struct cnic_dev *dev)
{
struct cnic_local *cp = dev->cnic_priv;
@@ -2482,11 +3759,402 @@ static int cnic_start_bnx2_hw(struct cnic_dev *dev)
return 0;
}
+static void cnic_setup_bnx2x_context(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ u32 start_offset = ethdev->ctx_tbl_offset;
+ int i;
+
+ for (i = 0; i < cp->ctx_blks; i++) {
+ struct cnic_ctx *ctx = &cp->ctx_arr[i];
+ dma_addr_t map = ctx->mapping;
+
+ if (cp->ctx_align) {
+ unsigned long mask = cp->ctx_align - 1;
+
+ map = (map + mask) & ~mask;
+ }
+
+ cnic_ctx_tbl_wr(dev, start_offset + i, map);
+ }
+}
+
+static int cnic_init_bnx2x_irq(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ int err = 0;
+
+ tasklet_init(&cp->cnic_irq_task, &cnic_service_bnx2x_bh,
+ (unsigned long) dev);
+ if (ethdev->drv_state & CNIC_DRV_STATE_USING_MSIX) {
+ err = request_irq(ethdev->irq_arr[0].vector, cnic_irq, 0,
+ "cnic", dev);
+ if (err)
+ tasklet_disable(&cp->cnic_irq_task);
+ }
+ return err;
+}
+
+static void cnic_enable_bnx2x_int(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u8 sb_id = cp->status_blk_num;
+ int port = CNIC_PORT(cp);
+
+ CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_SB_HC_TIMEOUT_C_OFFSET(port, sb_id,
+ HC_INDEX_C_ISCSI_EQ_CONS),
+ 64 / 12);
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_SB_HC_DISABLE_C_OFFSET(port, sb_id,
+ HC_INDEX_C_ISCSI_EQ_CONS), 0);
+}
+
+static void cnic_disable_bnx2x_int_sync(struct cnic_dev *dev)
+{
+}
+
+static void cnic_init_bnx2x_tx_ring(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ union eth_tx_bd_types *txbd = (union eth_tx_bd_types *) cp->l2_ring;
+ struct eth_context *context;
+ struct regpair context_addr;
+ dma_addr_t buf_map;
+ int func = CNIC_FUNC(cp);
+ int port = CNIC_PORT(cp);
+ int i;
+ int cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ u32 val;
+
+ memset(txbd, 0, BCM_PAGE_SIZE);
+
+ buf_map = cp->l2_buf_map;
+ for (i = 0; i < MAX_TX_DESC_CNT; i += 3, txbd += 3) {
+ struct eth_tx_start_bd *start_bd = &txbd->start_bd;
+ struct eth_tx_bd *reg_bd = &((txbd + 2)->reg_bd);
+
+ start_bd->addr_hi = cpu_to_le32((u64) buf_map >> 32);
+ start_bd->addr_lo = cpu_to_le32(buf_map & 0xffffffff);
+ reg_bd->addr_hi = start_bd->addr_hi;
+ reg_bd->addr_lo = start_bd->addr_lo + 0x10;
+ start_bd->nbytes = cpu_to_le16(0x10);
+ start_bd->nbd = cpu_to_le16(3);
+ start_bd->bd_flags.as_bitfield = ETH_TX_BD_FLAGS_START_BD;
+ start_bd->general_data = (UNICAST_ADDRESS <<
+ ETH_TX_START_BD_ETH_ADDR_TYPE_SHIFT);
+ start_bd->general_data |= (1 << ETH_TX_START_BD_HDR_NBDS_SHIFT);
+
+ }
+ context = cnic_get_bnx2x_ctx(dev, BNX2X_ISCSI_L2_CID, 1, &context_addr);
+
+ val = (u64) cp->l2_ring_map >> 32;
+ txbd->next_bd.addr_hi = cpu_to_le32(val);
+
+ context->xstorm_st_context.tx_bd_page_base_hi = val;
+
+ val = (u64) cp->l2_ring_map & 0xffffffff;
+ txbd->next_bd.addr_lo = cpu_to_le32(val);
+
+ context->xstorm_st_context.tx_bd_page_base_lo = val;
+
+ context->cstorm_st_context.sb_index_number =
+ HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS;
+ context->cstorm_st_context.status_block_id = BNX2X_DEF_SB_ID;
+
+ context->xstorm_st_context.statistics_data = (cli |
+ XSTORM_ETH_ST_CONTEXT_STATISTICS_ENABLE);
+
+ context->xstorm_ag_context.cdu_reserved =
+ CDU_RSRVD_VALUE_TYPE_A(BNX2X_HW_CID(BNX2X_ISCSI_L2_CID, func),
+ CDU_REGION_NUMBER_XCM_AG,
+ ETH_CONNECTION_TYPE);
+
+ /* reset xstorm per client statistics */
+ val = BAR_XSTRORM_INTMEM +
+ XSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
+ for (i = 0; i < sizeof(struct xstorm_per_client_stats) / 4; i++)
+ CNIC_WR(dev, val + i * 4, 0);
+
+ cp->tx_cons_ptr =
+ &cp->bnx2x_def_status_blk->c_def_status_block.index_values[
+ HC_INDEX_DEF_C_ETH_ISCSI_CQ_CONS];
+}
+
+static void cnic_init_bnx2x_rx_ring(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ struct eth_rx_bd *rxbd = (struct eth_rx_bd *) (cp->l2_ring +
+ BCM_PAGE_SIZE);
+ struct eth_rx_cqe_next_page *rxcqe = (struct eth_rx_cqe_next_page *)
+ (cp->l2_ring + (2 * BCM_PAGE_SIZE));
+ struct eth_context *context;
+ struct regpair context_addr;
+ int i;
+ int port = CNIC_PORT(cp);
+ int func = CNIC_FUNC(cp);
+ int cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ u32 val;
+ struct tstorm_eth_client_config tstorm_client = {0};
+
+ for (i = 0; i < BNX2X_MAX_RX_DESC_CNT; i++, rxbd++) {
+ dma_addr_t buf_map;
+ int n = (i % cp->l2_rx_ring_size) + 1;
+
+ buf_map = cp->l2_buf_map + (n * cp->l2_single_buf_size);
+ rxbd->addr_hi = cpu_to_le32((u64) buf_map >> 32);
+ rxbd->addr_lo = cpu_to_le32(buf_map & 0xffffffff);
+ }
+ context = cnic_get_bnx2x_ctx(dev, BNX2X_ISCSI_L2_CID, 0, &context_addr);
+
+ val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) >> 32;
+ rxbd->addr_hi = cpu_to_le32(val);
+
+ context->ustorm_st_context.common.bd_page_base_hi = val;
+
+ val = (u64) (cp->l2_ring_map + BCM_PAGE_SIZE) & 0xffffffff;
+ rxbd->addr_lo = cpu_to_le32(val);
+
+ context->ustorm_st_context.common.bd_page_base_lo = val;
+
+ context->ustorm_st_context.common.sb_index_numbers =
+ BNX2X_ISCSI_RX_SB_INDEX_NUM;
+ context->ustorm_st_context.common.clientId = cli;
+ context->ustorm_st_context.common.status_block_id = BNX2X_DEF_SB_ID;
+ context->ustorm_st_context.common.flags =
+ USTORM_ETH_ST_CONTEXT_CONFIG_ENABLE_STATISTICS;
+ context->ustorm_st_context.common.statistics_counter_id = cli;
+ context->ustorm_st_context.common.mc_alignment_log_size = 0;
+ context->ustorm_st_context.common.bd_buff_size =
+ cp->l2_single_buf_size;
+
+ context->ustorm_ag_context.cdu_usage =
+ CDU_RSRVD_VALUE_TYPE_A(BNX2X_HW_CID(BNX2X_ISCSI_L2_CID, func),
+ CDU_REGION_NUMBER_UCM_AG,
+ ETH_CONNECTION_TYPE);
+
+ rxcqe += BNX2X_MAX_RCQ_DESC_CNT;
+ val = (u64) (cp->l2_ring_map + (2 * BCM_PAGE_SIZE)) >> 32;
+ rxcqe->addr_hi = cpu_to_le32(val);
+
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_CQE_PAGE_BASE_OFFSET(port, cli) + 4, val);
+
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_CQE_PAGE_NEXT_OFFSET(port, cli) + 4, val);
+
+ val = (u64) (cp->l2_ring_map + (2 * BCM_PAGE_SIZE)) & 0xffffffff;
+ rxcqe->addr_lo = cpu_to_le32(val);
+
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_CQE_PAGE_BASE_OFFSET(port, cli), val);
+
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_CQE_PAGE_NEXT_OFFSET(port, cli), val);
+
+ /* client tstorm info */
+ tstorm_client.mtu = cp->l2_single_buf_size - 14;
+ tstorm_client.config_flags =
+ (TSTORM_ETH_CLIENT_CONFIG_E1HOV_REM_ENABLE |
+ TSTORM_ETH_CLIENT_CONFIG_STATSITICS_ENABLE);
+ tstorm_client.statistics_counter_id = cli;
+
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_CLIENT_CONFIG_OFFSET(port, cli),
+ ((u32 *)&tstorm_client)[0]);
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_CLIENT_CONFIG_OFFSET(port, cli) + 4,
+ ((u32 *)&tstorm_client)[1]);
+
+ /* reset tstorm per client statistics */
+ val = BAR_TSTRORM_INTMEM +
+ TSTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
+ for (i = 0; i < sizeof(struct tstorm_per_client_stats) / 4; i++)
+ CNIC_WR(dev, val + i * 4, 0);
+
+ /* reset ustorm per client statistics */
+ val = BAR_USTRORM_INTMEM +
+ USTORM_PER_COUNTER_ID_STATS_OFFSET(port, cli);
+ for (i = 0; i < sizeof(struct ustorm_per_client_stats) / 4; i++)
+ CNIC_WR(dev, val + i * 4, 0);
+
+ cp->rx_cons_ptr =
+ &cp->bnx2x_def_status_blk->u_def_status_block.index_values[
+ HC_INDEX_DEF_U_ETH_ISCSI_RX_CQ_CONS];
+}
+
+static void cnic_get_bnx2x_iscsi_info(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 base, addr, val;
+ int port = CNIC_PORT(cp);
+
+ dev->max_iscsi_conn = 0;
+ base = CNIC_RD(dev, MISC_REG_SHARED_MEM_ADDR);
+ if (base < 0xa0000 || base >= 0xc0000)
+ return;
+
+ val = BNX2X_SHMEM_ADDR(base,
+ dev_info.port_hw_config[port].iscsi_mac_upper);
+
+ dev->mac_addr[0] = (u8) (val >> 8);
+ dev->mac_addr[1] = (u8) val;
+
+ val = BNX2X_SHMEM_ADDR(base,
+ dev_info.port_hw_config[port].iscsi_mac_lower);
+
+ dev->mac_addr[2] = (u8) (val >> 24);
+ dev->mac_addr[3] = (u8) (val >> 16);
+ dev->mac_addr[4] = (u8) (val >> 8);
+ dev->mac_addr[5] = (u8) val;
+
+ addr = BNX2X_SHMEM_ADDR(base, validity_map[port]);
+ val = CNIC_RD(dev, addr);
+
+ if (!(val & SHR_MEM_VALIDITY_LIC_NO_KEY_IN_EFFECT)) {
+ u16 val16;
+
+ addr = BNX2X_SHMEM_ADDR(base,
+ drv_lic_key[port].max_iscsi_init_conn);
+ val16 = CNIC_RD16(dev, addr);
+
+ if (val16)
+ val16 ^= 0x1e1e;
+ dev->max_iscsi_conn = val16;
+ }
+ if (BNX2X_CHIP_IS_E1H(cp->chip_id)) {
+ int func = CNIC_FUNC(cp);
+
+ addr = BNX2X_SHMEM_ADDR(base,
+ mf_cfg.func_mf_config[func].e1hov_tag);
+ val = CNIC_RD(dev, addr);
+ val &= FUNC_MF_CFG_E1HOV_TAG_MASK;
+ if (val != FUNC_MF_CFG_E1HOV_TAG_DEFAULT) {
+ addr = BNX2X_SHMEM_ADDR(base,
+ mf_cfg.func_mf_config[func].config);
+ val = CNIC_RD(dev, addr);
+ val &= FUNC_MF_CFG_PROTOCOL_MASK;
+ if (val != FUNC_MF_CFG_PROTOCOL_ISCSI)
+ dev->max_iscsi_conn = 0;
+ }
+ }
+}
+
+static int cnic_start_bnx2x_hw(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ int func = CNIC_FUNC(cp), ret, i;
+ int port = CNIC_PORT(cp);
+ u16 eq_idx;
+ u8 sb_id = cp->status_blk_num;
+
+ ret = cnic_init_id_tbl(&cp->cid_tbl, MAX_ISCSI_TBL_SZ,
+ BNX2X_ISCSI_START_CID);
+
+ if (ret)
+ return -ENOMEM;
+
+ cp->kcq_io_addr = BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_PROD_OFFSET(func, 0);
+ cp->kcq_prod_idx = 0;
+
+ cnic_get_bnx2x_iscsi_info(dev);
+
+ /* Only 1 EQ */
+ CNIC_WR16(dev, cp->kcq_io_addr, MAX_KCQ_IDX);
+ CNIC_WR(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_CONS_OFFSET(func, 0), 0);
+ CNIC_WR(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0),
+ cp->kcq_info.pg_map_arr[1] & 0xffffffff);
+ CNIC_WR(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_OFFSET(func, 0) + 4,
+ (u64) cp->kcq_info.pg_map_arr[1] >> 32);
+ CNIC_WR(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0),
+ cp->kcq_info.pg_map_arr[0] & 0xffffffff);
+ CNIC_WR(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_NEXT_EQE_ADDR_OFFSET(func, 0) + 4,
+ (u64) cp->kcq_info.pg_map_arr[0] >> 32);
+ CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_NEXT_PAGE_ADDR_VALID_OFFSET(func, 0), 1);
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_SB_NUM_OFFSET(func, 0), cp->status_blk_num);
+ CNIC_WR8(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_ISCSI_EQ_SB_INDEX_OFFSET(func, 0),
+ HC_INDEX_C_ISCSI_EQ_CONS);
+
+ for (i = 0; i < cp->conn_buf_info.num_pages; i++) {
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(func, i),
+ cp->conn_buf_info.pgtbl[2 * i]);
+ CNIC_WR(dev, BAR_TSTRORM_INTMEM +
+ TSTORM_ISCSI_CONN_BUF_PBL_OFFSET(func, i) + 4,
+ cp->conn_buf_info.pgtbl[(2 * i) + 1]);
+ }
+
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(func),
+ cp->gbl_buf_info.pg_map_arr[0] & 0xffffffff);
+ CNIC_WR(dev, BAR_USTRORM_INTMEM +
+ USTORM_ISCSI_GLOBAL_BUF_PHYS_ADDR_OFFSET(func) + 4,
+ (u64) cp->gbl_buf_info.pg_map_arr[0] >> 32);
+
+ cnic_setup_bnx2x_context(dev);
+
+ eq_idx = CNIC_RD16(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id) +
+ offsetof(struct cstorm_status_block_c,
+ index_values[HC_INDEX_C_ISCSI_EQ_CONS]));
+ if (eq_idx != 0) {
+ printk(KERN_ERR PFX "%s: EQ cons index %x != 0\n",
+ dev->netdev->name, eq_idx);
+ return -EBUSY;
+ }
+ ret = cnic_init_bnx2x_irq(dev);
+ if (ret)
+ return ret;
+
+ cnic_init_bnx2x_tx_ring(dev);
+ cnic_init_bnx2x_rx_ring(dev);
+
+ return 0;
+}
+
static void cnic_init_rings(struct cnic_dev *dev)
{
if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
cnic_init_bnx2_tx_ring(dev);
cnic_init_bnx2_rx_ring(dev);
+ } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
+ struct cnic_local *cp = dev->cnic_priv;
+ struct cnic_eth_dev *ethdev = cp->ethdev;
+ u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+ union l5cm_specific_data l5_data;
+ struct ustorm_eth_rx_producers rx_prods = {0};
+ void __iomem *doorbell;
+ int i;
+
+ rx_prods.bd_prod = 0;
+ rx_prods.cqe_prod = BNX2X_MAX_RCQ_DESC_CNT;
+ barrier();
+
+ doorbell = ethdev->io_base2 + BAR_USTRORM_INTMEM +
+ USTORM_RX_PRODS_OFFSET(CNIC_PORT(cp), cli);
+
+ for (i = 0; i < sizeof(struct ustorm_eth_rx_producers) / 4; i++)
+ writel(((u32 *) &rx_prods)[i], doorbell + i * 4);
+
+ cnic_init_bnx2x_tx_ring(dev);
+ cnic_init_bnx2x_rx_ring(dev);
+
+ l5_data.phy_address.lo = cli;
+ l5_data.phy_address.hi = 0;
+ cnic_submit_kwqe_16(dev, RAMROD_CMD_ID_ETH_CLIENT_SETUP,
+ BNX2X_ISCSI_L2_CID, ETH_CONNECTION_TYPE, &l5_data);
+ cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 1);
}
}
@@ -2494,6 +4162,11 @@ static void cnic_shutdown_rings(struct cnic_dev *dev)
{
if (test_bit(CNIC_F_BNX2_CLASS, &dev->flags)) {
cnic_shutdown_bnx2_rx_ring(dev);
+ } else if (test_bit(CNIC_F_BNX2X_CLASS, &dev->flags)) {
+ struct cnic_local *cp = dev->cnic_priv;
+ u32 cli = BNX2X_ISCSI_CL_ID(CNIC_E1HVN(cp));
+
+ cnic_ring_ctl(dev, BNX2X_ISCSI_L2_CID, cli, 0);
}
}
@@ -2587,6 +4260,22 @@ static void cnic_stop_bnx2_hw(struct cnic_dev *dev)
cnic_free_resc(dev);
}
+
+static void cnic_stop_bnx2x_hw(struct cnic_dev *dev)
+{
+ struct cnic_local *cp = dev->cnic_priv;
+ u8 sb_id = cp->status_blk_num;
+ int port = CNIC_PORT(cp);
+
+ cnic_free_irq(dev);
+ CNIC_WR16(dev, BAR_CSTRORM_INTMEM +
+ CSTORM_SB_HOST_STATUS_BLOCK_C_OFFSET(port, sb_id) +
+ offsetof(struct cstorm_status_block_c,
+ index_values[HC_INDEX_C_ISCSI_EQ_CONS]),
+ 0);
+ cnic_free_resc(dev);
+}
+
static void cnic_stop_hw(struct cnic_dev *dev)
{
if (test_bit(CNIC_F_CNIC_UP, &dev->flags)) {
@@ -2718,6 +4407,57 @@ cnic_err:
return NULL;
}
+static struct cnic_dev *init_bnx2x_cnic(struct net_device *dev)
+{
+ struct pci_dev *pdev;
+ struct cnic_dev *cdev;
+ struct cnic_local *cp;
+ struct cnic_eth_dev *ethdev = NULL;
+ struct cnic_eth_dev *(*probe)(struct net_device *) = NULL;
+
+ probe = symbol_get(bnx2x_cnic_probe);
+ if (probe) {
+ ethdev = (*probe)(dev);
+ symbol_put(bnx2x_cnic_probe);
+ }
+ if (!ethdev)
+ return NULL;
+
+ pdev = ethdev->pdev;
+ if (!pdev)
+ return NULL;
+
+ dev_hold(dev);
+ cdev = cnic_alloc_dev(dev, pdev);
+ if (cdev == NULL) {
+ dev_put(dev);
+ return NULL;
+ }
+
+ set_bit(CNIC_F_BNX2X_CLASS, &cdev->flags);
+ cdev->submit_kwqes = cnic_submit_bnx2x_kwqes;
+
+ cp = cdev->cnic_priv;
+ cp->ethdev = ethdev;
+ cdev->pcidev = pdev;
+
+ cp->cnic_ops = &cnic_bnx2x_ops;
+ cp->start_hw = cnic_start_bnx2x_hw;
+ cp->stop_hw = cnic_stop_bnx2x_hw;
+ cp->setup_pgtbl = cnic_setup_page_tbl_le;
+ cp->alloc_resc = cnic_alloc_bnx2x_resc;
+ cp->free_resc = cnic_free_resc;
+ cp->start_cm = cnic_cm_init_bnx2x_hw;
+ cp->stop_cm = cnic_cm_stop_bnx2x_hw;
+ cp->enable_int = cnic_enable_bnx2x_int;
+ cp->disable_int_sync = cnic_disable_bnx2x_int_sync;
+ cp->ack_int = cnic_ack_bnx2x_msix;
+ cp->close_conn = cnic_close_bnx2x_conn;
+ cp->next_idx = cnic_bnx2x_next_idx;
+ cp->hw_idx = cnic_bnx2x_hw_idx;
+ return cdev;
+}
+
static struct cnic_dev *is_cnic_dev(struct net_device *dev)
{
struct ethtool_drvinfo drvinfo;
@@ -2729,6 +4469,8 @@ static struct cnic_dev *is_cnic_dev(struct net_device *dev)
if (!strcmp(drvinfo.driver, "bnx2"))
cdev = init_bnx2_cnic(dev);
+ if (!strcmp(drvinfo.driver, "bnx2x"))
+ cdev = init_bnx2x_cnic(dev);
if (cdev) {
write_lock(&cnic_dev_lock);
list_add(&cdev->list, &cnic_dev_list);
--
1.6.4.GIT
^ 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