* [net-next 7/7] ixgbe: bump version number
From: Jeff Kirsher @ 2012-11-28 13:06 UTC (permalink / raw)
To: davem; +Cc: Don Skidmore, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1354107978-24731-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Don Skidmore <donald.c.skidmore@intel.com>
Move the version string to better reflect the driver functionality with
that of the out of tree driver. Also since we no longer need the MAJ,
MIN, BUILD defines remove them to clean up the code.
Signed-off-by: Don Skidmore <donald.c.skidmore@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 6 +-----
1 file changed, 1 insertion(+), 5 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index fee0f8c..484bbed 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -63,11 +63,7 @@ char ixgbe_default_device_descr[] =
static char ixgbe_default_device_descr[] =
"Intel(R) 10 Gigabit Network Connection";
#endif
-#define MAJ 3
-#define MIN 9
-#define BUILD 15
-#define DRV_VERSION __stringify(MAJ) "." __stringify(MIN) "." \
- __stringify(BUILD) "-k"
+#define DRV_VERSION "3.11.33-k"
const char ixgbe_driver_version[] = DRV_VERSION;
static const char ixgbe_copyright[] =
"Copyright (c) 1999-2012 Intel Corporation.";
--
1.7.11.7
^ permalink raw reply related
* [net-next 6/7] ixgbe: Make the bridge mode setting sticky
From: Jeff Kirsher @ 2012-11-28 13:06 UTC (permalink / raw)
To: davem; +Cc: Greg Rose, netdev, gospo, sassmann, Jeff Kirsher
In-Reply-To: <1354107978-24731-1-git-send-email-jeffrey.t.kirsher@intel.com>
From: Greg Rose <gregory.v.rose@intel.com>
The internal bridge mode setting needs to be sticky so that it can be
configured correctly after a device reset. This change is required now
that the driver supports setting the bridge mode to VEB or VEPA.
Signed-off-by: Greg Rose <gregory.v.rose@intel.com>
Acked-by: John Fastabend <john.r.fastabend@intel.com>
Tested-by: Phil Schmitt <phillip.j.schmitt@intel.com>
Tested-by: Sibai Li <Sibai.li@intel.com>
Signed-off-by: Jeff Kirsher <jeffrey.t.kirsher@intel.com>
---
drivers/net/ethernet/intel/ixgbe/ixgbe.h | 1 +
drivers/net/ethernet/intel/ixgbe/ixgbe_main.c | 12 ++++++++----
drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c | 1 +
3 files changed, 10 insertions(+), 4 deletions(-)
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe.h b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
index 7ff4c4f..8e78676 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe.h
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe.h
@@ -483,6 +483,7 @@ struct ixgbe_adapter {
#define IXGBE_FLAG2_RSS_FIELD_IPV6_UDP (u32)(1 << 9)
#define IXGBE_FLAG2_PTP_ENABLED (u32)(1 << 10)
#define IXGBE_FLAG2_PTP_PPS_ENABLED (u32)(1 << 11)
+#define IXGBE_FLAG2_BRIDGE_MODE_VEB (u32)(1 << 12)
/* Tx fast path data */
int num_tx_queues;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
index fc8cfad..fee0f8c 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_main.c
@@ -3247,6 +3247,8 @@ static void ixgbe_configure_virtualization(struct ixgbe_adapter *adapter)
IXGBE_WRITE_REG(hw, IXGBE_VFRE(reg_offset ^ 1), reg_offset - 1);
IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset), (~0) << vf_shift);
IXGBE_WRITE_REG(hw, IXGBE_VFTE(reg_offset ^ 1), reg_offset - 1);
+ if (adapter->flags2 & IXGBE_FLAG2_BRIDGE_MODE_VEB)
+ IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
/* Map PF MAC address in RAR Entry 0 to first pool following VFs */
hw->mac.ops.set_vmdq(hw, 0, VMDQ_P(0));
@@ -7039,11 +7041,13 @@ static int ixgbe_ndo_bridge_setlink(struct net_device *dev,
continue;
mode = nla_get_u16(attr);
- if (mode == BRIDGE_MODE_VEPA)
+ if (mode == BRIDGE_MODE_VEPA) {
reg = 0;
- else if (mode == BRIDGE_MODE_VEB)
+ adapter->flags2 &= ~IXGBE_FLAG2_BRIDGE_MODE_VEB;
+ } else if (mode == BRIDGE_MODE_VEB) {
reg = IXGBE_PFDTXGSWC_VT_LBEN;
- else
+ adapter->flags2 |= IXGBE_FLAG2_BRIDGE_MODE_VEB;
+ } else
return -EINVAL;
IXGBE_WRITE_REG(&adapter->hw, IXGBE_PFDTXGSWC, reg);
@@ -7064,7 +7068,7 @@ static int ixgbe_ndo_bridge_getlink(struct sk_buff *skb, u32 pid, u32 seq,
if (!(adapter->flags & IXGBE_FLAG_SRIOV_ENABLED))
return 0;
- if (IXGBE_READ_REG(&adapter->hw, IXGBE_PFDTXGSWC) & 1)
+ if (adapter->flags2 & IXGBE_FLAG2_BRIDGE_MODE_VEB)
mode = BRIDGE_MODE_VEB;
else
mode = BRIDGE_MODE_VEPA;
diff --git a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
index 4993642..85cddac 100644
--- a/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
+++ b/drivers/net/ethernet/intel/ixgbe/ixgbe_sriov.c
@@ -119,6 +119,7 @@ void ixgbe_enable_sriov(struct ixgbe_adapter *adapter,
/* Initialize default switching mode VEB */
IXGBE_WRITE_REG(hw, IXGBE_PFDTXGSWC, IXGBE_PFDTXGSWC_VT_LBEN);
+ adapter->flags2 |= IXGBE_FLAG2_BRIDGE_MODE_VEB;
/* If call to enable VFs succeeded then allocate memory
* for per VF control structures.
--
1.7.11.7
^ permalink raw reply related
* Re: [PATCH v6 2/6] PM / Runtime: introduce pm_runtime_set_memalloc_noio()
From: Ming Lei @ 2012-11-28 13:51 UTC (permalink / raw)
To: Rafael J. Wysocki
Cc: linux-pm, linux-kernel, Alan Stern, Oliver Neukum, Minchan Kim,
Greg Kroah-Hartman, Jens Axboe, David S. Miller, Andrew Morton,
netdev, linux-usb, linux-mm
In-Reply-To: <2254856.YsOm9y7BK1@vostro.rjw.lan>
On Wed, Nov 28, 2012 at 6:06 PM, Rafael J. Wysocki <rjw@sisk.pl> wrote:
>
> Well, it may be unfrequent, but does it mean it has to do things that may
> be avoided (ie. walking the children of every node in the path in some cases)?
I agree so without introducing extra cost, :-)
> I don't really think that the counters would cost us that much anyway.
On ARM v7, sizeof(struct device) becomes 376 from 368 after introducing
'unsigned int noio_cnt;' to 'struct dev_pm_info', and total memory
increases about 3752bytes in a small configuration(about 494 device instance).
The actual memory increase should be more than the data because 'struct device'
is generally embedded into other concrete device structure.
>> Also looks the current implementation of pm_runtime_set_memalloc_noio()
>> is simple and clean enough with the flag, IMO.
>
> I know you always know better. :-)
We still need to consider cost and the function calling frequency, :-)
>
>> > I would use the flag only to store the information that
>> > pm_runtime_set_memalloc_noio(dev, true) has been run for this device directly
>> > and I'd use a counter for everything else.
>> >
>> > That is, have power.memalloc_count that would be incremented when (1)
>> > pm_runtime_set_memalloc_noio(dev, true) is called for that device and (2) when
>> > power.memalloc_count for one of its children changes from 0 to 1 (and
>> > analogously for decrementation). Then, check the counter in rpm_callback().
>>
>> Sorry, could you explain in a bit detail why we need the counter? Looks only
>> checking the flag in rpm_callback() is enough, doesn't it?
>
> Why would I want to use power.memalloc_count in addition to the
> power.memalloc_noio flag?
>
> Consider this:
>
> pm_runtime_set_memalloc_noio(dev):
> return if power.memalloc_noio is set
> set power.memalloc_noio
> loop:
> increment power.memalloc_count
> if power.memalloc_count is 1 now switch to parent and go to loop
I am wondering if the above should be changed to below because the child
count of memalloc_noio device need to be recorded.
pm_runtime_set_memalloc_noio(dev):
return if power.memalloc_noio is set
set power.memalloc_noio
loop:
increment power.memalloc_count
switch to parent and go to loop
So pm_runtime_set_memalloc_noio(dev) will become worse than
the improved pm_runtime_set_memalloc_noio(dev, true), which
can return immediately if one dev or parent's flag is true.
> pm_runtime_clear_memalloc_noio(dev):
> return if power.memalloc_noio is unset
> unset power.memalloc_noio
> loop:
> decrement power.memalloc_count
> if power.memalloc_count is 0 now switch to parent and go to loop
The above will perform well than pm_runtime_set_memalloc_noio(dev, false),
because the above avoids to walk children of device.
So one becomes worse and another becomes better, :-)
Also the children count of one device is generally very small, less than
10 for most devices, see the data obtained in one common x86 pc(thinkpad
t410) from below link:
http://kernel.ubuntu.com/~ming/up/t410-dev-child-cnt.log
- about 8 devices whose child count is more than 10, top three are 18, 17 ,12,
and all the three are root devices.
- about 117 devices whose child count is between 1 and 9
- other 501 devices whose child count is zero
>From above data, walking device children should have not much effect on
performance of pm_runtime_set_memalloc_noio(), which is also called in
very infrequent path.
> Looks kind of simpler, doesn't it?
Looks simpler, but more code lines than single
pm_runtime_set_memalloc_noio(), :-)
>
> And why rpm_callback() should check power.memalloc_count instead of the count?
> Because power.memalloc_noio will only be set for devices that
> pm_runtime_set_memalloc_noio(dev) was called for directly (not necessarily for
> the parents).
>
> And that works even if someone calls any of them twice in a row for the same
> device (presumably by mistake) and doesn't have to make any assumptions
> about devices it is called for.
IMO, we can ignore the mistake usage because the function is called only
in network/block core code currently, not by individual driver.
>
>> > Besides, don't you need to check children for the arg device itself?
>>
>> It isn't needed since the children of network/block device can't be
>> involved of the deadlock in runtime PM path.
>>
>> Also, the function is only called by network device or block device
>> subsystem, both the two kind of device are class device and should
>> have no children.
>
> OK, so not walking the arg device's children is an optimization related to
> some assumptions regarding who's supposed to use this routine. That should
> be clearly documented.
I think the patch already documents it in the comment of
pm_runtime_set_memalloc_noio().
Thanks,
--
Ming Lei
--
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
* [linux-next-20121127 pcnet32] warning at check_unmap()
From: Tetsuo Handa @ 2012-11-28 14:25 UTC (permalink / raw)
To: pcnet32; +Cc: netdev
dma_mapping_error() check seems to be missing at
static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb,
struct net_device *dev)
{
(...snipped...)
lp->tx_skbuff[entry] = skb;
lp->tx_dma_addr[entry] =
pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
// this line
lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]);
wmb(); /* Make sure owner changes after all others are visible */
lp->tx_ring[entry].status = cpu_to_le16(status);
(...snipped...)
}
but I don't know how to fix.
[ 20.908272] NET: Registered protocol family 10
[ 21.627711] pcnet32 0000:02:01.0 eth0: link up
[ 22.573436] ------------[ cut here ]------------
[ 22.574952] WARNING: at lib/dma-debug.c:933 check_unmap+0x4a6/0x920()
[ 22.575669] Hardware name: VMware Virtual Platform
[ 22.575669] pcnet32 0000:02:01.0: DMA-API: device driver failed to check map error[device address=0x000000001a3607f2] [size=90 bytes] [mapped as single]
[ 22.575669] Modules linked in: ipv6 binfmt_misc
[ 22.575669] Pid: 0, comm: swapper/1 Not tainted 3.7.0-rc7-next-20121127 #91
[ 22.575669] Call Trace:
[ 22.575669] [<c103370d>] warn_slowpath_common+0x6d/0xa0
[ 22.575669] [<c1249b46>] ? check_unmap+0x4a6/0x920
[ 22.575669] [<c1249b46>] ? check_unmap+0x4a6/0x920
[ 22.575669] [<c10337be>] warn_slowpath_fmt+0x2e/0x30
[ 22.575669] [<c1249b46>] check_unmap+0x4a6/0x920
[ 22.575669] [<c124a1bb>] debug_dma_unmap_page+0x5b/0x80
[ 22.575669] [<c13199be>] pcnet32_poll+0x45e/0x850
[ 22.575669] [<c105dc30>] ? __wake_up+0x40/0x50
[ 22.575669] [<c138dc70>] net_rx_action+0x90/0x140
[ 22.575669] [<c103b6f8>] __do_softirq+0x98/0x160
[ 22.575669] [<c103b660>] ? irq_enter+0x60/0x60
[ 22.575669] <IRQ> [<c103b52d>] ? irq_exit+0x7d/0x80
[ 22.575669] [<c1023cb4>] ? smp_apic_timer_interrupt+0x54/0x90
[ 22.575669] [<c1230fb4>] ? trace_hardirqs_off_thunk+0xc/0x18
[ 22.575669] [<c144c47e>] ? apic_timer_interrupt+0x32/0x38
[ 22.575669] [<c100a071>] ? default_idle+0x21/0x40
[ 22.575669] [<c100a729>] ? cpu_idle+0x69/0xc0
[ 22.575669] [<c1444e7e>] ? start_secondary+0x1b5/0x1bc
[ 22.575669] ---[ end trace d906affb5c70936d ]---
[ 22.575669] Mapped at:
[ 22.575669] [<c124a4c8>] debug_dma_map_page+0x68/0x140
[ 22.575669] [<c131acbb>] pcnet32_start_xmit+0x12b/0x220
[ 22.575669] [<c138bea6>] dev_hard_start_xmit+0x1d6/0x3d0
[ 22.575669] [<c13a3bc9>] sch_direct_xmit+0x99/0x240
[ 22.575669] [<c138e003>] dev_queue_xmit+0x143/0x5f0
^ permalink raw reply
* Re: [PATCH][RESEND] bonding: delete migrated IP addresses from the rlb hash table
From: Jiri Bohac @ 2012-11-28 14:38 UTC (permalink / raw)
To: Jay Vosburgh; +Cc: Jiri Bohac, Andy Gospodarek, netdev
In-Reply-To: <26343.1354064725@death.nxdomain>
On Tue, Nov 27, 2012 at 05:05:25PM -0800, Jay Vosburgh wrote:
> Jiri Bohac <jbohac@suse.cz> wrote:
> >Were there any results of your testing? Good or bad?
>
> I did test it quite a bit (and then neglected to follow up). I
> tried various deliberate hash collisions to try and make it fail in a
> corner case, but was unable to induce incorrect behavior.
Thanks for the review!
> The only issue I see is that a number of added lines run past 80
> columns, e.g.,
>
> + if (!(client_info->assigned && client_info->ip_src == arp->ip_src)) {
> + /* ip_src is going to be updated, fix the src hash list */
> + u32 hash_src = _simple_hash((u8 *)&arp->ip_src, sizeof(arp->ip_src));
>
> + * sending out client updates with this IP address and the old MAC address.
>
> + for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->used_next) {
>
> ... and so on.
I'll re-send a new version with all the >80 column lines fixed.
> I did not compile and test this version, just
> applied it and inspected it; presumably it is functionally identical to
> the prior version.
Yes, it's identical, only the comments and formatting changed.
> There's also one typo I noted near the end of the
> patch.
Fixed as well. Thanks!
--
Jiri Bohac <jbohac@suse.cz>
SUSE Labs, SUSE CZ
^ permalink raw reply
* Move an interface to init_ne
From: David Shwatrz @ 2012-11-28 14:39 UTC (permalink / raw)
To: netdev; +Cc: Eric W. Biederman
Hello,
How to I move an interface back to the original namespace ?
I created three namespaces:
ip netns add namespace1
ip netns add namespace2
ip netns add namespace3
And move eth0 to namespace1:
ip link set eth0 netns namespace1
How do I return it back to the original, default network namespace ? (init_net)
Regards,
DS
^ permalink raw reply
* Re: [PATCH][RESEND] bonding: delete migrated IP addresses from the rlb hash table
From: Jiri Bohac @ 2012-11-28 14:42 UTC (permalink / raw)
To: Jay Vosburgh; +Cc: Andy Gospodarek, netdev, David S. Miller
In-Reply-To: <20121128143853.GA2485@midget.suse.cz>
Bonding in balance-alb mode records information from ARP packets
passing through the bond in a hash table (rx_hashtbl).
At certain situations (e.g. link change of a slave),
rlb_update_rx_clients() will send out ARP packets to update ARP
caches of other hosts on the network to achieve RX load
balancing.
The problem is that once an IP address is recorded in the hash
table, it stays there indefinitely. If this IP address is
migrated to a different host in the network, bonding still sends
out ARP packets that poison other systems' ARP caches with
invalid information.
This patch solves this by looking at all incoming ARP packets,
and checking if the source IP address is one of the source
addresses stored in the rx_hashtbl. If it is, but the MAC
addresses differ, the corresponding hash table entries are
removed. Thus, when an IP address is migrated, the first ARP
broadcast by its new owner will purge the offending entries of
rx_hashtbl.
The hash table is hashed by ip_dst. To be able to do the above
check efficiently (not walking the whole hash table), we need a
reverse mapping (by ip_src).
I added three new members in struct rlb_client_info:
rx_hashtbl[x].src_first will point to the start of a list of
entries for which hash(ip_src) == x.
The list is linked with src_next and src_prev.
When an incoming ARP packet arrives at rlb_arp_recv()
rlb_purge_src_ip() can quickly walk only the entries on the
corresponding lists, i.e. the entries that are likely to contain
the offending IP address.
To avoid confusion, I renamed these existing fields of struct
rlb_client_info:
next -> used_next
prev -> used_prev
rx_hashtbl_head -> rx_hashtbl_used_head
(The current linked list is _not_ a list of hash table
entries with colliding ip_dst. It's a list of entries that are
being used; its purpose is to avoid walking the whole hash table
when looking for used entries.)
Signed-off-by: Jiri Bohac <jbohac@suse.cz>
diff --git a/drivers/net/bonding/bond_alb.c b/drivers/net/bonding/bond_alb.c
index e15cc11..74ce46a 100644
--- a/drivers/net/bonding/bond_alb.c
+++ b/drivers/net/bonding/bond_alb.c
@@ -84,6 +84,10 @@ static inline struct arp_pkt *arp_pkt(const struct sk_buff *skb)
/* Forward declaration */
static void alb_send_learning_packets(struct slave *slave, u8 mac_addr[]);
+static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp);
+static void rlb_src_unlink(struct bonding *bond, u32 index);
+static void rlb_src_link(struct bonding *bond, u32 ip_src_hash,
+ u32 ip_dst_hash);
static inline u8 _simple_hash(const u8 *hash_start, int hash_size)
{
@@ -354,6 +358,18 @@ static int rlb_arp_recv(const struct sk_buff *skb, struct bonding *bond,
if (!arp)
goto out;
+ /* We received an ARP from arp->ip_src.
+ * We might have used this IP address previously (on the bonding host
+ * itself or on a system that is bridged together with the bond).
+ * However, if arp->mac_src is different than what is stored in
+ * rx_hashtbl, some other host is now using the IP and we must prevent
+ * sending out client updates with this IP address and the old MAC
+ * address.
+ * Clean up all hash table entries that have this address as ip_src but
+ * have a different mac_src.
+ */
+ rlb_purge_src_ip(bond, arp);
+
if (arp->op_code == htons(ARPOP_REPLY)) {
/* update rx hash table for this ARP */
rlb_update_entry_from_arp(bond, arp);
@@ -432,9 +448,9 @@ static void rlb_clear_slave(struct bonding *bond, struct slave *slave)
_lock_rx_hashtbl_bh(bond);
rx_hash_table = bond_info->rx_hashtbl;
- index = bond_info->rx_hashtbl_head;
+ index = bond_info->rx_hashtbl_used_head;
for (; index != RLB_NULL_INDEX; index = next_index) {
- next_index = rx_hash_table[index].next;
+ next_index = rx_hash_table[index].used_next;
if (rx_hash_table[index].slave == slave) {
struct slave *assigned_slave = rlb_next_rx_slave(bond);
@@ -519,8 +535,9 @@ static void rlb_update_rx_clients(struct bonding *bond)
_lock_rx_hashtbl_bh(bond);
- hash_index = bond_info->rx_hashtbl_head;
- for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ hash_index = bond_info->rx_hashtbl_used_head;
+ for (; hash_index != RLB_NULL_INDEX;
+ hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
if (client_info->ntt) {
rlb_update_client(client_info);
@@ -548,8 +565,9 @@ static void rlb_req_update_slave_clients(struct bonding *bond, struct slave *sla
_lock_rx_hashtbl_bh(bond);
- hash_index = bond_info->rx_hashtbl_head;
- for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ hash_index = bond_info->rx_hashtbl_used_head;
+ for (; hash_index != RLB_NULL_INDEX;
+ hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
if ((client_info->slave == slave) &&
@@ -578,8 +596,9 @@ static void rlb_req_update_subnet_clients(struct bonding *bond, __be32 src_ip)
_lock_rx_hashtbl(bond);
- hash_index = bond_info->rx_hashtbl_head;
- for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ hash_index = bond_info->rx_hashtbl_used_head;
+ for (; hash_index != RLB_NULL_INDEX;
+ hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
if (!client_info->slave) {
@@ -625,6 +644,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
/* update mac address from arp */
memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);
}
+ memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN);
assigned_slave = client_info->slave;
if (assigned_slave) {
@@ -647,6 +667,17 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
assigned_slave = rlb_next_rx_slave(bond);
if (assigned_slave) {
+ if (!(client_info->assigned &&
+ client_info->ip_src == arp->ip_src)) {
+ /* ip_src is going to be updated,
+ * fix the src hash list
+ */
+ u32 hash_src = _simple_hash((u8 *)&arp->ip_src,
+ sizeof(arp->ip_src));
+ rlb_src_unlink(bond, hash_index);
+ rlb_src_link(bond, hash_src, hash_index);
+ }
+
client_info->ip_src = arp->ip_src;
client_info->ip_dst = arp->ip_dst;
/* arp->mac_dst is broadcast for arp reqeusts.
@@ -654,6 +685,7 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
* upon receiving an arp reply.
*/
memcpy(client_info->mac_dst, arp->mac_dst, ETH_ALEN);
+ memcpy(client_info->mac_src, arp->mac_src, ETH_ALEN);
client_info->slave = assigned_slave;
if (!ether_addr_equal_64bits(client_info->mac_dst, mac_bcast)) {
@@ -669,11 +701,11 @@ static struct slave *rlb_choose_channel(struct sk_buff *skb, struct bonding *bon
}
if (!client_info->assigned) {
- u32 prev_tbl_head = bond_info->rx_hashtbl_head;
- bond_info->rx_hashtbl_head = hash_index;
- client_info->next = prev_tbl_head;
+ u32 prev_tbl_head = bond_info->rx_hashtbl_used_head;
+ bond_info->rx_hashtbl_used_head = hash_index;
+ client_info->used_next = prev_tbl_head;
if (prev_tbl_head != RLB_NULL_INDEX) {
- bond_info->rx_hashtbl[prev_tbl_head].prev =
+ bond_info->rx_hashtbl[prev_tbl_head].used_prev =
hash_index;
}
client_info->assigned = 1;
@@ -740,8 +772,9 @@ static void rlb_rebalance(struct bonding *bond)
_lock_rx_hashtbl_bh(bond);
ntt = 0;
- hash_index = bond_info->rx_hashtbl_head;
- for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ hash_index = bond_info->rx_hashtbl_used_head;
+ for (; hash_index != RLB_NULL_INDEX;
+ hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
assigned_slave = rlb_next_rx_slave(bond);
if (assigned_slave && (client_info->slave != assigned_slave)) {
@@ -759,11 +792,113 @@ static void rlb_rebalance(struct bonding *bond)
}
/* Caller must hold rx_hashtbl lock */
+static void rlb_init_table_entry_dst(struct rlb_client_info *entry)
+{
+ entry->used_next = RLB_NULL_INDEX;
+ entry->used_prev = RLB_NULL_INDEX;
+ entry->assigned = 0;
+ entry->slave = NULL;
+ entry->tag = 0;
+}
+static void rlb_init_table_entry_src(struct rlb_client_info *entry)
+{
+ entry->src_first = RLB_NULL_INDEX;
+ entry->src_prev = RLB_NULL_INDEX;
+ entry->src_next = RLB_NULL_INDEX;
+}
+
static void rlb_init_table_entry(struct rlb_client_info *entry)
{
memset(entry, 0, sizeof(struct rlb_client_info));
- entry->next = RLB_NULL_INDEX;
- entry->prev = RLB_NULL_INDEX;
+ rlb_init_table_entry_dst(entry);
+ rlb_init_table_entry_src(entry);
+}
+
+static void rlb_delete_table_entry_dst(struct bonding *bond, u32 index)
+{
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ u32 next_index = bond_info->rx_hashtbl[index].used_next;
+ u32 prev_index = bond_info->rx_hashtbl[index].used_prev;
+
+ if (index == bond_info->rx_hashtbl_used_head)
+ bond_info->rx_hashtbl_used_head = next_index;
+ if (prev_index != RLB_NULL_INDEX)
+ bond_info->rx_hashtbl[prev_index].used_next = next_index;
+ if (next_index != RLB_NULL_INDEX)
+ bond_info->rx_hashtbl[next_index].used_prev = prev_index;
+}
+
+/* unlink a rlb hash table entry from the src list */
+static void rlb_src_unlink(struct bonding *bond, u32 index)
+{
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ u32 next_index = bond_info->rx_hashtbl[index].src_next;
+ u32 prev_index = bond_info->rx_hashtbl[index].src_prev;
+
+ bond_info->rx_hashtbl[index].src_next = RLB_NULL_INDEX;
+ bond_info->rx_hashtbl[index].src_prev = RLB_NULL_INDEX;
+
+ if (next_index != RLB_NULL_INDEX)
+ bond_info->rx_hashtbl[next_index].src_prev = prev_index;
+
+ if (prev_index == RLB_NULL_INDEX)
+ return;
+
+ /* is prev_index pointing to the head of this list? */
+ if (bond_info->rx_hashtbl[prev_index].src_first == index)
+ bond_info->rx_hashtbl[prev_index].src_first = next_index;
+ else
+ bond_info->rx_hashtbl[prev_index].src_next = next_index;
+
+}
+
+static void rlb_delete_table_entry(struct bonding *bond, u32 index)
+{
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ struct rlb_client_info *entry = &(bond_info->rx_hashtbl[index]);
+
+ rlb_delete_table_entry_dst(bond, index);
+ rlb_init_table_entry_dst(entry);
+
+ rlb_src_unlink(bond, index);
+}
+
+/* add the rx_hashtbl[ip_dst_hash] entry to the list
+ * of entries with identical ip_src_hash
+ */
+static void rlb_src_link(struct bonding *bond, u32 ip_src_hash, u32 ip_dst_hash)
+{
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ u32 next;
+
+ bond_info->rx_hashtbl[ip_dst_hash].src_prev = ip_src_hash;
+ next = bond_info->rx_hashtbl[ip_src_hash].src_first;
+ bond_info->rx_hashtbl[ip_dst_hash].src_next = next;
+ if (next != RLB_NULL_INDEX)
+ bond_info->rx_hashtbl[next].src_prev = ip_dst_hash;
+ bond_info->rx_hashtbl[ip_src_hash].src_first = ip_dst_hash;
+}
+
+/* deletes all rx_hashtbl entries with arp->ip_src if their mac_src does
+ * not match arp->mac_src */
+static void rlb_purge_src_ip(struct bonding *bond, struct arp_pkt *arp)
+{
+ struct alb_bond_info *bond_info = &(BOND_ALB_INFO(bond));
+ u32 ip_src_hash = _simple_hash((u8*)&(arp->ip_src), sizeof(arp->ip_src));
+ u32 index;
+
+ _lock_rx_hashtbl_bh(bond);
+
+ index = bond_info->rx_hashtbl[ip_src_hash].src_first;
+ while (index != RLB_NULL_INDEX) {
+ struct rlb_client_info *entry = &(bond_info->rx_hashtbl[index]);
+ u32 next_index = entry->src_next;
+ if (entry->ip_src == arp->ip_src &&
+ !ether_addr_equal_64bits(arp->mac_src, entry->mac_src))
+ rlb_delete_table_entry(bond, index);
+ index = next_index;
+ }
+ _unlock_rx_hashtbl_bh(bond);
}
static int rlb_initialize(struct bonding *bond)
@@ -781,7 +916,7 @@ static int rlb_initialize(struct bonding *bond)
bond_info->rx_hashtbl = new_hashtbl;
- bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
+ bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX;
for (i = 0; i < RLB_HASH_TABLE_SIZE; i++) {
rlb_init_table_entry(bond_info->rx_hashtbl + i);
@@ -803,7 +938,7 @@ static void rlb_deinitialize(struct bonding *bond)
kfree(bond_info->rx_hashtbl);
bond_info->rx_hashtbl = NULL;
- bond_info->rx_hashtbl_head = RLB_NULL_INDEX;
+ bond_info->rx_hashtbl_used_head = RLB_NULL_INDEX;
_unlock_rx_hashtbl_bh(bond);
}
@@ -815,25 +950,13 @@ static void rlb_clear_vlan(struct bonding *bond, unsigned short vlan_id)
_lock_rx_hashtbl_bh(bond);
- curr_index = bond_info->rx_hashtbl_head;
+ curr_index = bond_info->rx_hashtbl_used_head;
while (curr_index != RLB_NULL_INDEX) {
struct rlb_client_info *curr = &(bond_info->rx_hashtbl[curr_index]);
- u32 next_index = bond_info->rx_hashtbl[curr_index].next;
- u32 prev_index = bond_info->rx_hashtbl[curr_index].prev;
-
- if (curr->tag && (curr->vlan_id == vlan_id)) {
- if (curr_index == bond_info->rx_hashtbl_head) {
- bond_info->rx_hashtbl_head = next_index;
- }
- if (prev_index != RLB_NULL_INDEX) {
- bond_info->rx_hashtbl[prev_index].next = next_index;
- }
- if (next_index != RLB_NULL_INDEX) {
- bond_info->rx_hashtbl[next_index].prev = prev_index;
- }
+ u32 next_index = bond_info->rx_hashtbl[curr_index].used_next;
- rlb_init_table_entry(curr);
- }
+ if (curr->tag && (curr->vlan_id == vlan_id))
+ rlb_delete_table_entry(bond, curr_index);
curr_index = next_index;
}
diff --git a/drivers/net/bonding/bond_alb.h b/drivers/net/bonding/bond_alb.h
index 90f140a..e7a5b8b 100644
--- a/drivers/net/bonding/bond_alb.h
+++ b/drivers/net/bonding/bond_alb.h
@@ -94,15 +94,35 @@ struct tlb_client_info {
/* -------------------------------------------------------------------------
* struct rlb_client_info contains all info related to a specific rx client
- * connection. This is the Clients Hash Table entry struct
+ * connection. This is the Clients Hash Table entry struct.
+ * Note that this is not a proper hash table; if a new client's IP address
+ * hash collides with an existing client entry, the old entry is replaced.
+ *
+ * There is a linked list (linked by the used_next and used_prev members)
+ * linking all the used entries of the hash table. This allows updating
+ * all the clients without walking over all the unused elements of the table.
+ *
+ * There are also linked lists of entries with identical hash(ip_src). These
+ * allow cleaning up the table from ip_src<->mac_src associations that have
+ * become outdated and would cause sending out invalid ARP updates to the
+ * network. These are linked by the (src_next and src_prev members).
* -------------------------------------------------------------------------
*/
struct rlb_client_info {
__be32 ip_src; /* the server IP address */
__be32 ip_dst; /* the client IP address */
+ u8 mac_src[ETH_ALEN]; /* the server MAC address */
u8 mac_dst[ETH_ALEN]; /* the client MAC address */
- u32 next; /* The next Hash table entry index */
- u32 prev; /* The previous Hash table entry index */
+
+ /* list of used hash table entries, starting at rx_hashtbl_used_head */
+ u32 used_next;
+ u32 used_prev;
+
+ /* ip_src based hashing */
+ u32 src_next; /* next entry with same hash(ip_src) */
+ u32 src_prev; /* prev entry with same hash(ip_src) */
+ u32 src_first; /* first entry with hash(ip_src) == this entry's index */
+
u8 assigned; /* checking whether this entry is assigned */
u8 ntt; /* flag - need to transmit client info */
struct slave *slave; /* the slave assigned to this client */
@@ -131,7 +151,7 @@ struct alb_bond_info {
int rlb_enabled;
struct rlb_client_info *rx_hashtbl; /* Receive hash table */
spinlock_t rx_hashtbl_lock;
- u32 rx_hashtbl_head;
+ u32 rx_hashtbl_used_head;
u8 rx_ntt; /* flag - need to transmit
* to all rx clients
*/
diff --git a/drivers/net/bonding/bond_debugfs.c b/drivers/net/bonding/bond_debugfs.c
index 2cf084e..5fc4c23 100644
--- a/drivers/net/bonding/bond_debugfs.c
+++ b/drivers/net/bonding/bond_debugfs.c
@@ -31,8 +31,9 @@ static int bond_debug_rlb_hash_show(struct seq_file *m, void *v)
spin_lock_bh(&(BOND_ALB_INFO(bond).rx_hashtbl_lock));
- hash_index = bond_info->rx_hashtbl_head;
- for (; hash_index != RLB_NULL_INDEX; hash_index = client_info->next) {
+ hash_index = bond_info->rx_hashtbl_used_head;
+ for (; hash_index != RLB_NULL_INDEX;
+ hash_index = client_info->used_next) {
client_info = &(bond_info->rx_hashtbl[hash_index]);
seq_printf(m, "%-15pI4 %-15pI4 %-17pM %s\n",
&client_info->ip_src,
--
Jiri Bohac <jbohac@suse.cz>
SUSE Labs, SUSE CZ
^ permalink raw reply related
* [PATCH 1/6] qlcnic: create file qlcnic_io.c for datapath routines
From: Sony Chacko @ 2012-11-28 14:34 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
In-Reply-To: <1354113271-23850-1-git-send-email-sony.chacko@qlogic.com>
From: Sony Chacko <sony.chacko@qlogic.com>
Physical refactoring of 82xx adapter data path routines.
Move data path code to new file qlcnic_io.c
Existing data path code has coding stye issues, the code is
moved to the new file without fixing the style issues.
There is a seperate patch to fix the style issues in qlcnic_io.c
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/Makefile | 2 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 115 +--
drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c | 630 ----------
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 1346 ++++++++++++++++++++++
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 656 +-----------
5 files changed, 1373 insertions(+), 1376 deletions(-)
create mode 100644 drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
diff --git a/drivers/net/ethernet/qlogic/qlcnic/Makefile b/drivers/net/ethernet/qlogic/qlcnic/Makefile
index ddba83e..a26ee17 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/Makefile
+++ b/drivers/net/ethernet/qlogic/qlcnic/Makefile
@@ -5,4 +5,4 @@
obj-$(CONFIG_QLCNIC) := qlcnic.o
qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
- qlcnic_ethtool.o qlcnic_ctx.o
+ qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index ec29f79..db4508f 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -89,16 +89,6 @@
#define QLCNIC_CT_DEFAULT_RX_BUF_LEN 2048
#define QLCNIC_LRO_BUFFER_EXTRA 2048
-/* Opcodes to be used with the commands */
-#define TX_ETHER_PKT 0x01
-#define TX_TCP_PKT 0x02
-#define TX_UDP_PKT 0x03
-#define TX_IP_PKT 0x04
-#define TX_TCP_LSO 0x05
-#define TX_TCP_LSO6 0x06
-#define TX_TCPV6_PKT 0x0b
-#define TX_UDPV6_PKT 0x0c
-
/* Tx defines */
#define QLCNIC_MAX_FRAGS_PER_TX 14
#define MAX_TSO_HEADER_DESC 2
@@ -147,28 +137,6 @@
* Added fileds of tcpHdrSize and ipHdrSize, The driver needs to do it only when
* we are doing LSO (above the 1500 size packet) only.
*/
-
-#define FLAGS_VLAN_TAGGED 0x10
-#define FLAGS_VLAN_OOB 0x40
-
-#define qlcnic_set_tx_vlan_tci(cmd_desc, v) \
- (cmd_desc)->vlan_TCI = cpu_to_le16(v);
-#define qlcnic_set_cmd_desc_port(cmd_desc, var) \
- ((cmd_desc)->port_ctxid |= ((var) & 0x0F))
-#define qlcnic_set_cmd_desc_ctxid(cmd_desc, var) \
- ((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0))
-
-#define qlcnic_set_tx_port(_desc, _port) \
- ((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0))
-
-#define qlcnic_set_tx_flags_opcode(_desc, _flags, _opcode) \
- ((_desc)->flags_opcode |= \
- cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)))
-
-#define qlcnic_set_tx_frags_len(_desc, _frags, _len) \
- ((_desc)->nfrags__length = \
- cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8)))
-
struct cmd_desc_type0 {
u8 tcp_hdr_offset; /* For LSO only */
u8 ip_hdr_offset; /* For LSO only */
@@ -203,65 +171,6 @@ struct rcv_desc {
__le64 addr_buffer;
} __packed;
-/* opcode field in status_desc */
-#define QLCNIC_SYN_OFFLOAD 0x03
-#define QLCNIC_RXPKT_DESC 0x04
-#define QLCNIC_OLD_RXPKT_DESC 0x3f
-#define QLCNIC_RESPONSE_DESC 0x05
-#define QLCNIC_LRO_DESC 0x12
-
-/* for status field in status_desc */
-#define STATUS_CKSUM_LOOP 0
-#define STATUS_CKSUM_OK 2
-
-/* owner bits of status_desc */
-#define STATUS_OWNER_HOST (0x1ULL << 56)
-#define STATUS_OWNER_PHANTOM (0x2ULL << 56)
-
-/* Status descriptor:
- 0-3 port, 4-7 status, 8-11 type, 12-27 total_length
- 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset
- 53-55 desc_cnt, 56-57 owner, 58-63 opcode
- */
-#define qlcnic_get_sts_port(sts_data) \
- ((sts_data) & 0x0F)
-#define qlcnic_get_sts_status(sts_data) \
- (((sts_data) >> 4) & 0x0F)
-#define qlcnic_get_sts_type(sts_data) \
- (((sts_data) >> 8) & 0x0F)
-#define qlcnic_get_sts_totallength(sts_data) \
- (((sts_data) >> 12) & 0xFFFF)
-#define qlcnic_get_sts_refhandle(sts_data) \
- (((sts_data) >> 28) & 0xFFFF)
-#define qlcnic_get_sts_prot(sts_data) \
- (((sts_data) >> 44) & 0x0F)
-#define qlcnic_get_sts_pkt_offset(sts_data) \
- (((sts_data) >> 48) & 0x1F)
-#define qlcnic_get_sts_desc_cnt(sts_data) \
- (((sts_data) >> 53) & 0x7)
-#define qlcnic_get_sts_opcode(sts_data) \
- (((sts_data) >> 58) & 0x03F)
-
-#define qlcnic_get_lro_sts_refhandle(sts_data) \
- ((sts_data) & 0x0FFFF)
-#define qlcnic_get_lro_sts_length(sts_data) \
- (((sts_data) >> 16) & 0x0FFFF)
-#define qlcnic_get_lro_sts_l2_hdr_offset(sts_data) \
- (((sts_data) >> 32) & 0x0FF)
-#define qlcnic_get_lro_sts_l4_hdr_offset(sts_data) \
- (((sts_data) >> 40) & 0x0FF)
-#define qlcnic_get_lro_sts_timestamp(sts_data) \
- (((sts_data) >> 48) & 0x1)
-#define qlcnic_get_lro_sts_type(sts_data) \
- (((sts_data) >> 49) & 0x7)
-#define qlcnic_get_lro_sts_push_flag(sts_data) \
- (((sts_data) >> 52) & 0x1)
-#define qlcnic_get_lro_sts_seq_number(sts_data) \
- ((sts_data) & 0x0FFFFFFFF)
-#define qlcnic_get_lro_sts_mss(sts_data1) \
- ((sts_data1 >> 32) & 0x0FFFF)
-
-
struct status_desc {
__le64 status_desc_data[2];
} __attribute__ ((aligned(16)));
@@ -1648,6 +1557,15 @@ int qlcnic_clear_esw_stats(struct qlcnic_adapter *adapter, u8, u8, u8);
int qlcnic_get_mac_stats(struct qlcnic_adapter *, struct qlcnic_mac_statistics *);
extern int qlcnic_config_tso;
+int qlcnic_napi_add(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_napi_del(struct qlcnic_adapter *adapter);
+void qlcnic_napi_enable(struct qlcnic_adapter *adapter);
+void qlcnic_napi_disable(struct qlcnic_adapter *adapter);
+int qlcnic_alloc_sds_rings(struct qlcnic_recv_context *, int);
+void qlcnic_free_sds_rings(struct qlcnic_recv_context *);
+void qlcnic_free_tx_rings(struct qlcnic_adapter *);
+int qlcnic_alloc_tx_rings(struct qlcnic_adapter *, struct net_device *);
+
/*
* QLOGIC Board information
*/
@@ -1694,6 +1612,21 @@ static inline u32 qlcnic_tx_avail(struct qlcnic_host_tx_ring *tx_ring)
tx_ring->producer;
}
+static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
+{
+ writel(0, sds_ring->crb_intr_mask);
+}
+
+static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
+{
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+ writel(0x1, sds_ring->crb_intr_mask);
+
+ if (!QLCNIC_IS_MSI_FAMILY(adapter))
+ writel(0xfbff, adapter->tgt_mask_reg);
+}
+
extern const struct ethtool_ops qlcnic_ethtool_ops;
extern const struct ethtool_ops qlcnic_ethtool_failed_ops;
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
index ccbef84..d8610ea 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_init.c
@@ -25,10 +25,6 @@ static unsigned int crb_addr_xform[QLCNIC_MAX_CRB_XFORM];
#define QLCNIC_ADDR_ERROR (0xffffffff)
-static void
-qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring);
-
static int
qlcnic_check_fw_hearbeat(struct qlcnic_adapter *adapter);
@@ -1332,629 +1328,3 @@ qlcnic_release_firmware(struct qlcnic_adapter *adapter)
release_firmware(adapter->fw);
adapter->fw = NULL;
}
-
-static void
-qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
- struct qlcnic_fw_msg *msg)
-{
- u32 cable_OUI;
- u16 cable_len;
- u16 link_speed;
- u8 link_status, module, duplex, autoneg;
- u8 lb_status = 0;
- struct net_device *netdev = adapter->netdev;
-
- adapter->has_link_events = 1;
-
- cable_OUI = msg->body[1] & 0xffffffff;
- cable_len = (msg->body[1] >> 32) & 0xffff;
- link_speed = (msg->body[1] >> 48) & 0xffff;
-
- link_status = msg->body[2] & 0xff;
- duplex = (msg->body[2] >> 16) & 0xff;
- autoneg = (msg->body[2] >> 24) & 0xff;
- lb_status = (msg->body[2] >> 32) & 0x3;
-
- module = (msg->body[2] >> 8) & 0xff;
- if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE)
- dev_info(&netdev->dev, "unsupported cable: OUI 0x%x, "
- "length %d\n", cable_OUI, cable_len);
- else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN)
- dev_info(&netdev->dev, "unsupported cable length %d\n",
- cable_len);
-
- if (!link_status && (lb_status == QLCNIC_ILB_MODE ||
- lb_status == QLCNIC_ELB_MODE))
- adapter->ahw->loopback_state |= QLCNIC_LINKEVENT;
-
- qlcnic_advert_link_change(adapter, link_status);
-
- if (duplex == LINKEVENT_FULL_DUPLEX)
- adapter->link_duplex = DUPLEX_FULL;
- else
- adapter->link_duplex = DUPLEX_HALF;
-
- adapter->module_type = module;
- adapter->link_autoneg = autoneg;
-
- if (link_status) {
- adapter->link_speed = link_speed;
- } else {
- adapter->link_speed = SPEED_UNKNOWN;
- adapter->link_duplex = DUPLEX_UNKNOWN;
- }
-}
-
-static void
-qlcnic_handle_fw_message(int desc_cnt, int index,
- struct qlcnic_host_sds_ring *sds_ring)
-{
- struct qlcnic_fw_msg msg;
- struct status_desc *desc;
- struct qlcnic_adapter *adapter;
- struct device *dev;
- int i = 0, opcode, ret;
-
- while (desc_cnt > 0 && i < 8) {
- desc = &sds_ring->desc_head[index];
- msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]);
- msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]);
-
- index = get_next_index(index, sds_ring->num_desc);
- desc_cnt--;
- }
-
- adapter = sds_ring->adapter;
- dev = &adapter->pdev->dev;
- opcode = qlcnic_get_nic_msg_opcode(msg.body[0]);
-
- switch (opcode) {
- case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE:
- qlcnic_handle_linkevent(adapter, &msg);
- break;
- case QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK:
- ret = (u32)(msg.body[1]);
- switch (ret) {
- case 0:
- adapter->ahw->loopback_state |= QLCNIC_LB_RESPONSE;
- break;
- case 1:
- dev_info(dev, "loopback already in progress\n");
- adapter->diag_cnt = -QLCNIC_TEST_IN_PROGRESS;
- break;
- case 2:
- dev_info(dev, "loopback cable is not connected\n");
- adapter->diag_cnt = -QLCNIC_LB_CABLE_NOT_CONN;
- break;
- default:
- dev_info(dev, "loopback configure request failed,"
- " ret %x\n", ret);
- adapter->diag_cnt = -QLCNIC_UNDEFINED_ERROR;
- break;
- }
- break;
- default:
- break;
- }
-}
-
-static int
-qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring,
- struct qlcnic_rx_buffer *buffer)
-{
- struct sk_buff *skb;
- dma_addr_t dma;
- struct pci_dev *pdev = adapter->pdev;
-
- skb = netdev_alloc_skb(adapter->netdev, rds_ring->skb_size);
- if (!skb) {
- adapter->stats.skb_alloc_failure++;
- return -ENOMEM;
- }
-
- skb_reserve(skb, NET_IP_ALIGN);
-
- dma = pci_map_single(pdev, skb->data,
- rds_ring->dma_size, PCI_DMA_FROMDEVICE);
-
- if (pci_dma_mapping_error(pdev, dma)) {
- adapter->stats.rx_dma_map_error++;
- dev_kfree_skb_any(skb);
- return -ENOMEM;
- }
-
- buffer->skb = skb;
- buffer->dma = dma;
-
- return 0;
-}
-
-static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring, u16 index, u16 cksum)
-{
- struct qlcnic_rx_buffer *buffer;
- struct sk_buff *skb;
-
- buffer = &rds_ring->rx_buf_arr[index];
-
- if (unlikely(buffer->skb == NULL)) {
- WARN_ON(1);
- return NULL;
- }
-
- pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
- PCI_DMA_FROMDEVICE);
-
- skb = buffer->skb;
-
- if (likely((adapter->netdev->features & NETIF_F_RXCSUM) &&
- (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
- adapter->stats.csummed++;
- skb->ip_summed = CHECKSUM_UNNECESSARY;
- } else {
- skb_checksum_none_assert(skb);
- }
-
- buffer->skb = NULL;
-
- return skb;
-}
-
-static inline int
-qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb,
- u16 *vlan_tag)
-{
- struct ethhdr *eth_hdr;
-
- if (!__vlan_get_tag(skb, vlan_tag)) {
- eth_hdr = (struct ethhdr *) skb->data;
- memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
- skb_pull(skb, VLAN_HLEN);
- }
- if (!adapter->pvid)
- return 0;
-
- if (*vlan_tag == adapter->pvid) {
- /* Outer vlan tag. Packet should follow non-vlan path */
- *vlan_tag = 0xffff;
- return 0;
- }
- if (adapter->flags & QLCNIC_TAGGING_ENABLED)
- return 0;
-
- return -EINVAL;
-}
-
-static struct qlcnic_rx_buffer *
-qlcnic_process_rcv(struct qlcnic_adapter *adapter,
- struct qlcnic_host_sds_ring *sds_ring,
- int ring, u64 sts_data0)
-{
- struct net_device *netdev = adapter->netdev;
- struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
- struct qlcnic_rx_buffer *buffer;
- struct sk_buff *skb;
- struct qlcnic_host_rds_ring *rds_ring;
- int index, length, cksum, pkt_offset;
- u16 vid = 0xffff;
-
- if (unlikely(ring >= adapter->max_rds_rings))
- return NULL;
-
- rds_ring = &recv_ctx->rds_rings[ring];
-
- index = qlcnic_get_sts_refhandle(sts_data0);
- if (unlikely(index >= rds_ring->num_desc))
- return NULL;
-
- buffer = &rds_ring->rx_buf_arr[index];
-
- length = qlcnic_get_sts_totallength(sts_data0);
- cksum = qlcnic_get_sts_status(sts_data0);
- pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
-
- skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
- if (!skb)
- return buffer;
-
- if (length > rds_ring->skb_size)
- skb_put(skb, rds_ring->skb_size);
- else
- skb_put(skb, length);
-
- if (pkt_offset)
- skb_pull(skb, pkt_offset);
-
- if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
- adapter->stats.rxdropped++;
- dev_kfree_skb(skb);
- return buffer;
- }
-
- skb->protocol = eth_type_trans(skb, netdev);
-
- if (vid != 0xffff)
- __vlan_hwaccel_put_tag(skb, vid);
-
- napi_gro_receive(&sds_ring->napi, skb);
-
- adapter->stats.rx_pkts++;
- adapter->stats.rxbytes += length;
-
- return buffer;
-}
-
-#define QLC_TCP_HDR_SIZE 20
-#define QLC_TCP_TS_OPTION_SIZE 12
-#define QLC_TCP_TS_HDR_SIZE (QLC_TCP_HDR_SIZE + QLC_TCP_TS_OPTION_SIZE)
-
-static struct qlcnic_rx_buffer *
-qlcnic_process_lro(struct qlcnic_adapter *adapter,
- int ring, u64 sts_data0, u64 sts_data1)
-{
- struct net_device *netdev = adapter->netdev;
- struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
- struct qlcnic_rx_buffer *buffer;
- struct sk_buff *skb;
- struct qlcnic_host_rds_ring *rds_ring;
- struct iphdr *iph;
- struct tcphdr *th;
- bool push, timestamp;
- int l2_hdr_offset, l4_hdr_offset;
- int index;
- u16 lro_length, length, data_offset;
- u32 seq_number;
- u16 vid = 0xffff;
-
- if (unlikely(ring > adapter->max_rds_rings))
- return NULL;
-
- rds_ring = &recv_ctx->rds_rings[ring];
-
- index = qlcnic_get_lro_sts_refhandle(sts_data0);
- if (unlikely(index > rds_ring->num_desc))
- return NULL;
-
- buffer = &rds_ring->rx_buf_arr[index];
-
- timestamp = qlcnic_get_lro_sts_timestamp(sts_data0);
- lro_length = qlcnic_get_lro_sts_length(sts_data0);
- l2_hdr_offset = qlcnic_get_lro_sts_l2_hdr_offset(sts_data0);
- l4_hdr_offset = qlcnic_get_lro_sts_l4_hdr_offset(sts_data0);
- push = qlcnic_get_lro_sts_push_flag(sts_data0);
- seq_number = qlcnic_get_lro_sts_seq_number(sts_data1);
-
- skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
- if (!skb)
- return buffer;
-
- if (timestamp)
- data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
- else
- data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE;
-
- skb_put(skb, lro_length + data_offset);
-
- skb_pull(skb, l2_hdr_offset);
-
- if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
- adapter->stats.rxdropped++;
- dev_kfree_skb(skb);
- return buffer;
- }
-
- skb->protocol = eth_type_trans(skb, netdev);
-
- iph = (struct iphdr *)skb->data;
- th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
-
- length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
- iph->tot_len = htons(length);
- iph->check = 0;
- iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
- th->psh = push;
- th->seq = htonl(seq_number);
-
- length = skb->len;
-
- if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
- skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);
-
- if (vid != 0xffff)
- __vlan_hwaccel_put_tag(skb, vid);
- netif_receive_skb(skb);
-
- adapter->stats.lro_pkts++;
- adapter->stats.lrobytes += length;
-
- return buffer;
-}
-
-int
-qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
-{
- struct qlcnic_adapter *adapter = sds_ring->adapter;
- struct list_head *cur;
- struct status_desc *desc;
- struct qlcnic_rx_buffer *rxbuf;
- u64 sts_data0, sts_data1;
-
- int count = 0;
- int opcode, ring, desc_cnt;
- u32 consumer = sds_ring->consumer;
-
- while (count < max) {
- desc = &sds_ring->desc_head[consumer];
- sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
-
- if (!(sts_data0 & STATUS_OWNER_HOST))
- break;
-
- desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
- opcode = qlcnic_get_sts_opcode(sts_data0);
-
- switch (opcode) {
- case QLCNIC_RXPKT_DESC:
- case QLCNIC_OLD_RXPKT_DESC:
- case QLCNIC_SYN_OFFLOAD:
- ring = qlcnic_get_sts_type(sts_data0);
- rxbuf = qlcnic_process_rcv(adapter, sds_ring,
- ring, sts_data0);
- break;
- case QLCNIC_LRO_DESC:
- ring = qlcnic_get_lro_sts_type(sts_data0);
- sts_data1 = le64_to_cpu(desc->status_desc_data[1]);
- rxbuf = qlcnic_process_lro(adapter, ring, sts_data0,
- sts_data1);
- break;
- case QLCNIC_RESPONSE_DESC:
- qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
- default:
- goto skip;
- }
-
- WARN_ON(desc_cnt > 1);
-
- if (likely(rxbuf))
- list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
- else
- adapter->stats.null_rxbuf++;
-
-skip:
- for (; desc_cnt > 0; desc_cnt--) {
- desc = &sds_ring->desc_head[consumer];
- desc->status_desc_data[0] =
- cpu_to_le64(STATUS_OWNER_PHANTOM);
- consumer = get_next_index(consumer, sds_ring->num_desc);
- }
- count++;
- }
-
- for (ring = 0; ring < adapter->max_rds_rings; ring++) {
- struct qlcnic_host_rds_ring *rds_ring =
- &adapter->recv_ctx->rds_rings[ring];
-
- if (!list_empty(&sds_ring->free_list[ring])) {
- list_for_each(cur, &sds_ring->free_list[ring]) {
- rxbuf = list_entry(cur,
- struct qlcnic_rx_buffer, list);
- qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
- }
- spin_lock(&rds_ring->lock);
- list_splice_tail_init(&sds_ring->free_list[ring],
- &rds_ring->free_list);
- spin_unlock(&rds_ring->lock);
- }
-
- qlcnic_post_rx_buffers_nodb(adapter, rds_ring);
- }
-
- if (count) {
- sds_ring->consumer = consumer;
- writel(consumer, sds_ring->crb_sts_consumer);
- }
-
- return count;
-}
-
-void
-qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring)
-{
- struct rcv_desc *pdesc;
- struct qlcnic_rx_buffer *buffer;
- int count = 0;
- u32 producer;
- struct list_head *head;
-
- producer = rds_ring->producer;
-
- head = &rds_ring->free_list;
- while (!list_empty(head)) {
-
- buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
-
- if (!buffer->skb) {
- if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
- break;
- }
-
- count++;
- list_del(&buffer->list);
-
- /* make a rcv descriptor */
- pdesc = &rds_ring->desc_head[producer];
- pdesc->addr_buffer = cpu_to_le64(buffer->dma);
- pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
- pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
-
- producer = get_next_index(producer, rds_ring->num_desc);
- }
-
- if (count) {
- rds_ring->producer = producer;
- writel((producer-1) & (rds_ring->num_desc-1),
- rds_ring->crb_rcv_producer);
- }
-}
-
-static void
-qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring)
-{
- struct rcv_desc *pdesc;
- struct qlcnic_rx_buffer *buffer;
- int count = 0;
- uint32_t producer;
- struct list_head *head;
-
- if (!spin_trylock(&rds_ring->lock))
- return;
-
- producer = rds_ring->producer;
-
- head = &rds_ring->free_list;
- while (!list_empty(head)) {
-
- buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
-
- if (!buffer->skb) {
- if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
- break;
- }
-
- count++;
- list_del(&buffer->list);
-
- /* make a rcv descriptor */
- pdesc = &rds_ring->desc_head[producer];
- pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
- pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
- pdesc->addr_buffer = cpu_to_le64(buffer->dma);
-
- producer = get_next_index(producer, rds_ring->num_desc);
- }
-
- if (count) {
- rds_ring->producer = producer;
- writel((producer - 1) & (rds_ring->num_desc - 1),
- rds_ring->crb_rcv_producer);
- }
- spin_unlock(&rds_ring->lock);
-}
-
-static void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter)
-{
- int i;
- unsigned char *data = skb->data;
-
- printk(KERN_INFO "\n");
- for (i = 0; i < skb->len; i++) {
- QLCDB(adapter, DRV, "%02x ", data[i]);
- if ((i & 0x0f) == 8)
- printk(KERN_INFO "\n");
- }
-}
-
-static void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, int ring,
- u64 sts_data0)
-{
- struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
- struct sk_buff *skb;
- struct qlcnic_host_rds_ring *rds_ring;
- int index, length, cksum, pkt_offset;
-
- if (unlikely(ring >= adapter->max_rds_rings))
- return;
-
- rds_ring = &recv_ctx->rds_rings[ring];
-
- index = qlcnic_get_sts_refhandle(sts_data0);
- length = qlcnic_get_sts_totallength(sts_data0);
- if (unlikely(index >= rds_ring->num_desc))
- return;
-
- cksum = qlcnic_get_sts_status(sts_data0);
- pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
-
- skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
- if (!skb)
- return;
-
- if (length > rds_ring->skb_size)
- skb_put(skb, rds_ring->skb_size);
- else
- skb_put(skb, length);
-
- if (pkt_offset)
- skb_pull(skb, pkt_offset);
-
- if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
- adapter->diag_cnt++;
- else
- dump_skb(skb, adapter);
-
- dev_kfree_skb_any(skb);
- adapter->stats.rx_pkts++;
- adapter->stats.rxbytes += length;
-
- return;
-}
-
-void
-qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
-{
- struct qlcnic_adapter *adapter = sds_ring->adapter;
- struct status_desc *desc;
- u64 sts_data0;
- int ring, opcode, desc_cnt;
-
- u32 consumer = sds_ring->consumer;
-
- desc = &sds_ring->desc_head[consumer];
- sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
-
- if (!(sts_data0 & STATUS_OWNER_HOST))
- return;
-
- desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
- opcode = qlcnic_get_sts_opcode(sts_data0);
- switch (opcode) {
- case QLCNIC_RESPONSE_DESC:
- qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
- break;
- default:
- ring = qlcnic_get_sts_type(sts_data0);
- qlcnic_process_rcv_diag(adapter, ring, sts_data0);
- break;
- }
-
- for (; desc_cnt > 0; desc_cnt--) {
- desc = &sds_ring->desc_head[consumer];
- desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
- consumer = get_next_index(consumer, sds_ring->num_desc);
- }
-
- sds_ring->consumer = consumer;
- writel(consumer, sds_ring->crb_sts_consumer);
-}
-
-void qlcnic_fetch_mac(u32 off1, u32 off2, u8 alt_mac, u8 *mac)
-{
- u32 mac_low, mac_high;
- int i;
-
- mac_low = off1;
- mac_high = off2;
-
- if (alt_mac) {
- mac_low |= (mac_low >> 16) | (mac_high << 16);
- mac_high >>= 16;
- }
-
- for (i = 0; i < 2; i++)
- mac[i] = (u8)(mac_high >> ((1 - i) * 8));
- for (i = 2; i < 6; i++)
- mac[i] = (u8)(mac_low >> ((5 - i) * 8));
-}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
new file mode 100644
index 0000000..25e6ffc
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -0,0 +1,1346 @@
+#include <linux/netdevice.h>
+#include <linux/if_vlan.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+
+#include "qlcnic.h"
+
+#define QLCNIC_MAC_HASH(MAC)\
+ ((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
+
+#define TX_ETHER_PKT 0x01
+#define TX_TCP_PKT 0x02
+#define TX_UDP_PKT 0x03
+#define TX_IP_PKT 0x04
+#define TX_TCP_LSO 0x05
+#define TX_TCP_LSO6 0x06
+#define TX_TCPV6_PKT 0x0b
+#define TX_UDPV6_PKT 0x0c
+#define FLAGS_VLAN_TAGGED 0x10
+#define FLAGS_VLAN_OOB 0x40
+
+#define qlcnic_set_tx_vlan_tci(cmd_desc, v) \
+ (cmd_desc)->vlan_TCI = cpu_to_le16(v);
+#define qlcnic_set_cmd_desc_port(cmd_desc, var) \
+ ((cmd_desc)->port_ctxid |= ((var) & 0x0F))
+#define qlcnic_set_cmd_desc_ctxid(cmd_desc, var) \
+ ((cmd_desc)->port_ctxid |= ((var) << 4 & 0xF0))
+
+#define qlcnic_set_tx_port(_desc, _port) \
+ ((_desc)->port_ctxid = ((_port) & 0xf) | (((_port) << 4) & 0xf0))
+
+#define qlcnic_set_tx_flags_opcode(_desc, _flags, _opcode) \
+ ((_desc)->flags_opcode |= \
+ cpu_to_le16(((_flags) & 0x7f) | (((_opcode) & 0x3f) << 7)))
+
+#define qlcnic_set_tx_frags_len(_desc, _frags, _len) \
+ ((_desc)->nfrags__length = \
+ cpu_to_le32(((_frags) & 0xff) | (((_len) & 0xffffff) << 8)))
+
+/* owner bits of status_desc */
+#define STATUS_OWNER_HOST (0x1ULL << 56)
+#define STATUS_OWNER_PHANTOM (0x2ULL << 56)
+
+/* Status descriptor:
+ 0-3 port, 4-7 status, 8-11 type, 12-27 total_length
+ 28-43 reference_handle, 44-47 protocol, 48-52 pkt_offset
+ 53-55 desc_cnt, 56-57 owner, 58-63 opcode
+ */
+#define qlcnic_get_sts_port(sts_data) \
+ ((sts_data) & 0x0F)
+#define qlcnic_get_sts_status(sts_data) \
+ (((sts_data) >> 4) & 0x0F)
+#define qlcnic_get_sts_type(sts_data) \
+ (((sts_data) >> 8) & 0x0F)
+#define qlcnic_get_sts_totallength(sts_data) \
+ (((sts_data) >> 12) & 0xFFFF)
+#define qlcnic_get_sts_refhandle(sts_data) \
+ (((sts_data) >> 28) & 0xFFFF)
+#define qlcnic_get_sts_prot(sts_data) \
+ (((sts_data) >> 44) & 0x0F)
+#define qlcnic_get_sts_pkt_offset(sts_data) \
+ (((sts_data) >> 48) & 0x1F)
+#define qlcnic_get_sts_desc_cnt(sts_data) \
+ (((sts_data) >> 53) & 0x7)
+#define qlcnic_get_sts_opcode(sts_data) \
+ (((sts_data) >> 58) & 0x03F)
+
+#define qlcnic_get_lro_sts_refhandle(sts_data) \
+ ((sts_data) & 0x0FFFF)
+#define qlcnic_get_lro_sts_length(sts_data) \
+ (((sts_data) >> 16) & 0x0FFFF)
+#define qlcnic_get_lro_sts_l2_hdr_offset(sts_data) \
+ (((sts_data) >> 32) & 0x0FF)
+#define qlcnic_get_lro_sts_l4_hdr_offset(sts_data) \
+ (((sts_data) >> 40) & 0x0FF)
+#define qlcnic_get_lro_sts_timestamp(sts_data) \
+ (((sts_data) >> 48) & 0x1)
+#define qlcnic_get_lro_sts_type(sts_data) \
+ (((sts_data) >> 49) & 0x7)
+#define qlcnic_get_lro_sts_push_flag(sts_data) \
+ (((sts_data) >> 52) & 0x1)
+#define qlcnic_get_lro_sts_seq_number(sts_data) \
+ ((sts_data) & 0x0FFFFFFFF)
+#define qlcnic_get_lro_sts_mss(sts_data1) \
+ ((sts_data1 >> 32) & 0x0FFFF)
+
+/* opcode field in status_desc */
+#define QLCNIC_SYN_OFFLOAD 0x03
+#define QLCNIC_RXPKT_DESC 0x04
+#define QLCNIC_OLD_RXPKT_DESC 0x3f
+#define QLCNIC_RESPONSE_DESC 0x05
+#define QLCNIC_LRO_DESC 0x12
+
+/* for status field in status_desc */
+#define STATUS_CKSUM_LOOP 0
+#define STATUS_CKSUM_OK 2
+static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
+ u64 uaddr, __le16 vlan_id, struct qlcnic_host_tx_ring *tx_ring)
+{
+ struct cmd_desc_type0 *hwdesc;
+ struct qlcnic_nic_req *req;
+ struct qlcnic_mac_req *mac_req;
+ struct qlcnic_vlan_req *vlan_req;
+ u32 producer;
+ u64 word;
+
+ producer = tx_ring->producer;
+ hwdesc = &tx_ring->desc_head[tx_ring->producer];
+
+ req = (struct qlcnic_nic_req *)hwdesc;
+ memset(req, 0, sizeof(struct qlcnic_nic_req));
+ req->qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
+
+ word = QLCNIC_MAC_EVENT | ((u64)(adapter->portnum) << 16);
+ req->req_hdr = cpu_to_le64(word);
+
+ mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
+ mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
+ memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
+
+ vlan_req = (struct qlcnic_vlan_req *)&req->words[1];
+ vlan_req->vlan_id = vlan_id;
+
+ tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
+ smp_mb();
+}
+
+static void
+qlcnic_send_filter(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring,
+ struct cmd_desc_type0 *first_desc,
+ struct sk_buff *skb)
+{
+ struct ethhdr *phdr = (struct ethhdr *)(skb->data);
+ struct qlcnic_filter *fil, *tmp_fil;
+ struct hlist_node *tmp_hnode, *n;
+ struct hlist_head *head;
+ u64 src_addr = 0;
+ __le16 vlan_id = 0;
+ u8 hindex;
+
+ if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
+ return;
+
+ if (adapter->fhash.fnum >= adapter->fhash.fmax)
+ return;
+
+ /* Only NPAR capable devices support vlan based learning*/
+ if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
+ vlan_id = first_desc->vlan_TCI;
+ memcpy(&src_addr, phdr->h_source, ETH_ALEN);
+ hindex = QLCNIC_MAC_HASH(src_addr) & (QLCNIC_LB_MAX_FILTERS - 1);
+ head = &(adapter->fhash.fhead[hindex]);
+
+ hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
+ if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
+ tmp_fil->vlan_id == vlan_id) {
+
+ if (jiffies >
+ (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
+ qlcnic_change_filter(adapter, src_addr, vlan_id,
+ tx_ring);
+ tmp_fil->ftime = jiffies;
+ return;
+ }
+ }
+
+ fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
+ if (!fil)
+ return;
+
+ qlcnic_change_filter(adapter, src_addr, vlan_id, tx_ring);
+
+ fil->ftime = jiffies;
+ fil->vlan_id = vlan_id;
+ memcpy(fil->faddr, &src_addr, ETH_ALEN);
+ spin_lock(&adapter->mac_learn_lock);
+ hlist_add_head(&(fil->fnode), head);
+ adapter->fhash.fnum++;
+ spin_unlock(&adapter->mac_learn_lock);
+}
+
+static int
+qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
+ struct cmd_desc_type0 *first_desc,
+ struct sk_buff *skb)
+{
+ u8 opcode = 0, hdr_len = 0;
+ u16 flags = 0, vlan_tci = 0;
+ int copied, offset, copy_len;
+ struct cmd_desc_type0 *hwdesc;
+ struct vlan_ethhdr *vh;
+ struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+ u16 protocol = ntohs(skb->protocol);
+ u32 producer = tx_ring->producer;
+
+ if (protocol == ETH_P_8021Q) {
+ vh = (struct vlan_ethhdr *)skb->data;
+ flags = FLAGS_VLAN_TAGGED;
+ vlan_tci = ntohs(vh->h_vlan_TCI);
+ protocol = ntohs(vh->h_vlan_encapsulated_proto);
+ } else if (vlan_tx_tag_present(skb)) {
+ flags = FLAGS_VLAN_OOB;
+ vlan_tci = vlan_tx_tag_get(skb);
+ }
+ if (unlikely(adapter->pvid)) {
+ if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED))
+ return -EIO;
+ if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))
+ goto set_flags;
+
+ flags = FLAGS_VLAN_OOB;
+ vlan_tci = adapter->pvid;
+ }
+set_flags:
+ qlcnic_set_tx_vlan_tci(first_desc, vlan_tci);
+ qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
+
+ if (*(skb->data) & BIT_0) {
+ flags |= BIT_0;
+ memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
+ }
+ opcode = TX_ETHER_PKT;
+ if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
+ skb_shinfo(skb)->gso_size > 0) {
+
+ hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
+
+ first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
+ first_desc->total_hdr_length = hdr_len;
+
+ opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO;
+
+ /* For LSO, we need to copy the MAC/IP/TCP headers into
+ * the descriptor ring */
+ copied = 0;
+ offset = 2;
+
+ if (flags & FLAGS_VLAN_OOB) {
+ first_desc->total_hdr_length += VLAN_HLEN;
+ first_desc->tcp_hdr_offset = VLAN_HLEN;
+ first_desc->ip_hdr_offset = VLAN_HLEN;
+ /* Only in case of TSO on vlan device */
+ flags |= FLAGS_VLAN_TAGGED;
+
+ /* Create a TSO vlan header template for firmware */
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) -
+ offset, hdr_len + VLAN_HLEN);
+
+ vh = (struct vlan_ethhdr *)((char *) hwdesc + 2);
+ skb_copy_from_linear_data(skb, vh, 12);
+ vh->h_vlan_proto = htons(ETH_P_8021Q);
+ vh->h_vlan_TCI = htons(vlan_tci);
+
+ skb_copy_from_linear_data_offset(skb, 12,
+ (char *)vh + 16, copy_len - 16);
+
+ copied = copy_len - VLAN_HLEN;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ while (copied < hdr_len) {
+
+ copy_len = min((int)sizeof(struct cmd_desc_type0) -
+ offset, (hdr_len - copied));
+
+ hwdesc = &tx_ring->desc_head[producer];
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+
+ skb_copy_from_linear_data_offset(skb, copied,
+ (char *) hwdesc + offset, copy_len);
+
+ copied += copy_len;
+ offset = 0;
+
+ producer = get_next_index(producer, tx_ring->num_desc);
+ }
+
+ tx_ring->producer = producer;
+ smp_mb();
+ adapter->stats.lso_frames++;
+
+ } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
+ u8 l4proto;
+
+ if (protocol == ETH_P_IP) {
+ l4proto = ip_hdr(skb)->protocol;
+
+ if (l4proto == IPPROTO_TCP)
+ opcode = TX_TCP_PKT;
+ else if (l4proto == IPPROTO_UDP)
+ opcode = TX_UDP_PKT;
+ } else if (protocol == ETH_P_IPV6) {
+ l4proto = ipv6_hdr(skb)->nexthdr;
+
+ if (l4proto == IPPROTO_TCP)
+ opcode = TX_TCPV6_PKT;
+ else if (l4proto == IPPROTO_UDP)
+ opcode = TX_UDPV6_PKT;
+ }
+ }
+ first_desc->tcp_hdr_offset += skb_transport_offset(skb);
+ first_desc->ip_hdr_offset += skb_network_offset(skb);
+ qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
+
+ return 0;
+}
+
+static int
+qlcnic_map_tx_skb(struct pci_dev *pdev,
+ struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
+{
+ struct qlcnic_skb_frag *nf;
+ struct skb_frag_struct *frag;
+ int i, nr_frags;
+ dma_addr_t map;
+
+ nr_frags = skb_shinfo(skb)->nr_frags;
+ nf = &pbuf->frag_array[0];
+
+ map = pci_map_single(pdev, skb->data,
+ skb_headlen(skb), PCI_DMA_TODEVICE);
+ if (pci_dma_mapping_error(pdev, map))
+ goto out_err;
+
+ nf->dma = map;
+ nf->length = skb_headlen(skb);
+
+ for (i = 0; i < nr_frags; i++) {
+ frag = &skb_shinfo(skb)->frags[i];
+ nf = &pbuf->frag_array[i+1];
+
+ map = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
+ DMA_TO_DEVICE);
+ if (dma_mapping_error(&pdev->dev, map))
+ goto unwind;
+
+ nf->dma = map;
+ nf->length = skb_frag_size(frag);
+ }
+
+ return 0;
+
+unwind:
+ while (--i >= 0) {
+ nf = &pbuf->frag_array[i+1];
+ pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
+ }
+
+ nf = &pbuf->frag_array[0];
+ pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
+
+out_err:
+ return -ENOMEM;
+}
+
+static void
+qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb,
+ struct qlcnic_cmd_buffer *pbuf)
+{
+ struct qlcnic_skb_frag *nf = &pbuf->frag_array[0];
+ int nr_frags = skb_shinfo(skb)->nr_frags;
+ int i;
+
+ for (i = 0; i < nr_frags; i++) {
+ nf = &pbuf->frag_array[i+1];
+ pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
+ }
+
+ nf = &pbuf->frag_array[0];
+ pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
+ pbuf->skb = NULL;
+}
+
+static inline void
+qlcnic_clear_cmddesc(u64 *desc)
+{
+ desc[0] = 0ULL;
+ desc[2] = 0ULL;
+ desc[7] = 0ULL;
+}
+
+netdev_tx_t
+qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+{
+ struct qlcnic_adapter *adapter = netdev_priv(netdev);
+ struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+ struct qlcnic_cmd_buffer *pbuf;
+ struct qlcnic_skb_frag *buffrag;
+ struct cmd_desc_type0 *hwdesc, *first_desc;
+ struct pci_dev *pdev;
+ struct ethhdr *phdr;
+ int delta = 0;
+ int i, k;
+
+ u32 producer;
+ int frag_count;
+ u32 num_txd = tx_ring->num_desc;
+
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+ netif_stop_queue(netdev);
+ return NETDEV_TX_BUSY;
+ }
+
+ if (adapter->flags & QLCNIC_MACSPOOF) {
+ phdr = (struct ethhdr *)skb->data;
+ if (!ether_addr_equal(phdr->h_source, adapter->mac_addr))
+ goto drop_packet;
+ }
+
+ frag_count = skb_shinfo(skb)->nr_frags + 1;
+ /* 14 frags supported for normal packet and
+ * 32 frags supported for TSO packet
+ */
+ if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) {
+
+ for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++)
+ delta += skb_frag_size(&skb_shinfo(skb)->frags[i]);
+
+ if (!__pskb_pull_tail(skb, delta))
+ goto drop_packet;
+
+ frag_count = 1 + skb_shinfo(skb)->nr_frags;
+ }
+
+ if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
+ netif_stop_queue(netdev);
+ if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
+ netif_start_queue(netdev);
+ else {
+ adapter->stats.xmit_off++;
+ return NETDEV_TX_BUSY;
+ }
+ }
+
+ producer = tx_ring->producer;
+ pbuf = &tx_ring->cmd_buf_arr[producer];
+
+ pdev = adapter->pdev;
+
+ first_desc = hwdesc = &tx_ring->desc_head[producer];
+ qlcnic_clear_cmddesc((u64 *)hwdesc);
+
+ if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
+ adapter->stats.tx_dma_map_error++;
+ goto drop_packet;
+ }
+
+ pbuf->skb = skb;
+ pbuf->frag_count = frag_count;
+
+ qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
+ qlcnic_set_tx_port(first_desc, adapter->portnum);
+
+ for (i = 0; i < frag_count; i++) {
+
+ k = i % 4;
+
+ if ((k == 0) && (i > 0)) {
+ /* move to next desc.*/
+ producer = get_next_index(producer, num_txd);
+ hwdesc = &tx_ring->desc_head[producer];
+ qlcnic_clear_cmddesc((u64 *)hwdesc);
+ tx_ring->cmd_buf_arr[producer].skb = NULL;
+ }
+
+ buffrag = &pbuf->frag_array[i];
+
+ hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
+ switch (k) {
+ case 0:
+ hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
+ break;
+ case 1:
+ hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma);
+ break;
+ case 2:
+ hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma);
+ break;
+ case 3:
+ hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma);
+ break;
+ }
+ }
+
+ tx_ring->producer = get_next_index(producer, num_txd);
+ smp_mb();
+
+ if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb)))
+ goto unwind_buff;
+
+ if (adapter->mac_learn)
+ qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
+
+ adapter->stats.txbytes += skb->len;
+ adapter->stats.xmitcalled++;
+
+ qlcnic_update_cmd_producer(tx_ring);
+
+ return NETDEV_TX_OK;
+
+unwind_buff:
+ qlcnic_unmap_buffers(pdev, skb, pbuf);
+drop_packet:
+ adapter->stats.txdropped++;
+ dev_kfree_skb_any(skb);
+ return NETDEV_TX_OK;
+}
+
+void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
+{
+ struct net_device *netdev = adapter->netdev;
+
+ if (adapter->ahw->linkup && !linkup) {
+ netdev_info(netdev, "NIC Link is down\n");
+ adapter->ahw->linkup = 0;
+ if (netif_running(netdev)) {
+ netif_carrier_off(netdev);
+ netif_stop_queue(netdev);
+ }
+ } else if (!adapter->ahw->linkup && linkup) {
+ netdev_info(netdev, "NIC Link is up\n");
+ adapter->ahw->linkup = 1;
+ if (netif_running(netdev)) {
+ netif_carrier_on(netdev);
+ netif_wake_queue(netdev);
+ }
+ }
+}
+
+static int
+qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring,
+ struct qlcnic_rx_buffer *buffer)
+{
+ struct sk_buff *skb;
+ dma_addr_t dma;
+ struct pci_dev *pdev = adapter->pdev;
+
+ skb = netdev_alloc_skb(adapter->netdev, rds_ring->skb_size);
+ if (!skb) {
+ adapter->stats.skb_alloc_failure++;
+ return -ENOMEM;
+ }
+
+ skb_reserve(skb, NET_IP_ALIGN);
+
+ dma = pci_map_single(pdev, skb->data,
+ rds_ring->dma_size, PCI_DMA_FROMDEVICE);
+
+ if (pci_dma_mapping_error(pdev, dma)) {
+ adapter->stats.rx_dma_map_error++;
+ dev_kfree_skb_any(skb);
+ return -ENOMEM;
+ }
+
+ buffer->skb = skb;
+ buffer->dma = dma;
+
+ return 0;
+}
+
+static void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring)
+{
+ struct rcv_desc *pdesc;
+ struct qlcnic_rx_buffer *buffer;
+ int count = 0;
+ uint32_t producer;
+ struct list_head *head;
+
+ if (!spin_trylock(&rds_ring->lock))
+ return;
+
+ producer = rds_ring->producer;
+
+ head = &rds_ring->free_list;
+ while (!list_empty(head)) {
+
+ buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
+
+ if (!buffer->skb) {
+ if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
+ break;
+ }
+
+ count++;
+ list_del(&buffer->list);
+
+ /* make a rcv descriptor */
+ pdesc = &rds_ring->desc_head[producer];
+ pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+ pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
+ pdesc->addr_buffer = cpu_to_le64(buffer->dma);
+
+ producer = get_next_index(producer, rds_ring->num_desc);
+ }
+
+ if (count) {
+ rds_ring->producer = producer;
+ writel((producer - 1) & (rds_ring->num_desc - 1),
+ rds_ring->crb_rcv_producer);
+ }
+ spin_unlock(&rds_ring->lock);
+}
+
+static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
+{
+ u32 sw_consumer, hw_consumer;
+ int count = 0, i;
+ struct qlcnic_cmd_buffer *buffer;
+ struct pci_dev *pdev = adapter->pdev;
+ struct net_device *netdev = adapter->netdev;
+ struct qlcnic_skb_frag *frag;
+ int done;
+ struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
+
+ if (!spin_trylock(&adapter->tx_clean_lock))
+ return 1;
+
+ sw_consumer = tx_ring->sw_consumer;
+ hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
+
+ while (sw_consumer != hw_consumer) {
+ buffer = &tx_ring->cmd_buf_arr[sw_consumer];
+ if (buffer->skb) {
+ frag = &buffer->frag_array[0];
+ pci_unmap_single(pdev, frag->dma, frag->length,
+ PCI_DMA_TODEVICE);
+ frag->dma = 0ULL;
+ for (i = 1; i < buffer->frag_count; i++) {
+ frag++;
+ pci_unmap_page(pdev, frag->dma, frag->length,
+ PCI_DMA_TODEVICE);
+ frag->dma = 0ULL;
+ }
+
+ adapter->stats.xmitfinished++;
+ dev_kfree_skb_any(buffer->skb);
+ buffer->skb = NULL;
+ }
+
+ sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
+ if (++count >= MAX_STATUS_HANDLE)
+ break;
+ }
+
+ if (count && netif_running(netdev)) {
+ tx_ring->sw_consumer = sw_consumer;
+
+ smp_mb();
+
+ if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
+ if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
+ netif_wake_queue(netdev);
+ adapter->stats.xmit_on++;
+ }
+ }
+ adapter->tx_timeo_cnt = 0;
+ }
+ /*
+ * If everything is freed up to consumer then check if the ring is full
+ * If the ring is full then check if more needs to be freed and
+ * schedule the call back again.
+ *
+ * This happens when there are 2 CPUs. One could be freeing and the
+ * other filling it. If the ring is full when we get out of here and
+ * the card has already interrupted the host then the host can miss the
+ * interrupt.
+ *
+ * There is still a possible race condition and the host could miss an
+ * interrupt. The card has to take care of this.
+ */
+ hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
+ done = (sw_consumer == hw_consumer);
+ spin_unlock(&adapter->tx_clean_lock);
+
+ return done;
+}
+
+static int qlcnic_poll(struct napi_struct *napi, int budget)
+{
+ struct qlcnic_host_sds_ring *sds_ring =
+ container_of(napi, struct qlcnic_host_sds_ring, napi);
+
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+
+ int tx_complete;
+ int work_done;
+
+ tx_complete = qlcnic_process_cmd_ring(adapter);
+
+ work_done = qlcnic_process_rcv_ring(sds_ring, budget);
+
+ if ((work_done < budget) && tx_complete) {
+ napi_complete(&sds_ring->napi);
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+ qlcnic_enable_int(sds_ring);
+ }
+
+ return work_done;
+}
+
+static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
+{
+ struct qlcnic_host_sds_ring *sds_ring =
+ container_of(napi, struct qlcnic_host_sds_ring, napi);
+
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+ int work_done;
+
+ work_done = qlcnic_process_rcv_ring(sds_ring, budget);
+
+ if (work_done < budget) {
+ napi_complete(&sds_ring->napi);
+ if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
+ qlcnic_enable_int(sds_ring);
+ }
+
+ return work_done;
+}
+
+static void
+qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
+ struct qlcnic_fw_msg *msg)
+{
+ u32 cable_OUI;
+ u16 cable_len;
+ u16 link_speed;
+ u8 link_status, module, duplex, autoneg;
+ u8 lb_status = 0;
+ struct net_device *netdev = adapter->netdev;
+
+ adapter->has_link_events = 1;
+
+ cable_OUI = msg->body[1] & 0xffffffff;
+ cable_len = (msg->body[1] >> 32) & 0xffff;
+ link_speed = (msg->body[1] >> 48) & 0xffff;
+
+ link_status = msg->body[2] & 0xff;
+ duplex = (msg->body[2] >> 16) & 0xff;
+ autoneg = (msg->body[2] >> 24) & 0xff;
+ lb_status = (msg->body[2] >> 32) & 0x3;
+
+ module = (msg->body[2] >> 8) & 0xff;
+ if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE)
+ dev_info(&netdev->dev, "unsupported cable: OUI 0x%x, "
+ "length %d\n", cable_OUI, cable_len);
+ else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN)
+ dev_info(&netdev->dev, "unsupported cable length %d\n",
+ cable_len);
+
+ if (!link_status && (lb_status == QLCNIC_ILB_MODE ||
+ lb_status == QLCNIC_ELB_MODE))
+ adapter->ahw->loopback_state |= QLCNIC_LINKEVENT;
+
+ qlcnic_advert_link_change(adapter, link_status);
+
+ if (duplex == LINKEVENT_FULL_DUPLEX)
+ adapter->link_duplex = DUPLEX_FULL;
+ else
+ adapter->link_duplex = DUPLEX_HALF;
+
+ adapter->module_type = module;
+ adapter->link_autoneg = autoneg;
+
+ if (link_status) {
+ adapter->link_speed = link_speed;
+ } else {
+ adapter->link_speed = SPEED_UNKNOWN;
+ adapter->link_duplex = DUPLEX_UNKNOWN;
+ }
+}
+
+static void
+qlcnic_handle_fw_message(int desc_cnt, int index,
+ struct qlcnic_host_sds_ring *sds_ring)
+{
+ struct qlcnic_fw_msg msg;
+ struct status_desc *desc;
+ struct qlcnic_adapter *adapter;
+ struct device *dev;
+ int i = 0, opcode, ret;
+
+ while (desc_cnt > 0 && i < 8) {
+ desc = &sds_ring->desc_head[index];
+ msg.words[i++] = le64_to_cpu(desc->status_desc_data[0]);
+ msg.words[i++] = le64_to_cpu(desc->status_desc_data[1]);
+
+ index = get_next_index(index, sds_ring->num_desc);
+ desc_cnt--;
+ }
+
+ adapter = sds_ring->adapter;
+ dev = &adapter->pdev->dev;
+ opcode = qlcnic_get_nic_msg_opcode(msg.body[0]);
+
+ switch (opcode) {
+ case QLCNIC_C2H_OPCODE_GET_LINKEVENT_RESPONSE:
+ qlcnic_handle_linkevent(adapter, &msg);
+ break;
+ case QLCNIC_C2H_OPCODE_CONFIG_LOOPBACK:
+ ret = (u32)(msg.body[1]);
+ switch (ret) {
+ case 0:
+ adapter->ahw->loopback_state |= QLCNIC_LB_RESPONSE;
+ break;
+ case 1:
+ dev_info(dev, "loopback already in progress\n");
+ adapter->diag_cnt = -QLCNIC_TEST_IN_PROGRESS;
+ break;
+ case 2:
+ dev_info(dev, "loopback cable is not connected\n");
+ adapter->diag_cnt = -QLCNIC_LB_CABLE_NOT_CONN;
+ break;
+ default:
+ dev_info(dev, "loopback configure request failed,"
+ " ret %x\n", ret);
+ adapter->diag_cnt = -QLCNIC_UNDEFINED_ERROR;
+ break;
+ }
+ break;
+ default:
+ break;
+ }
+}
+
+static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring, u16 index, u16 cksum)
+{
+ struct qlcnic_rx_buffer *buffer;
+ struct sk_buff *skb;
+
+ buffer = &rds_ring->rx_buf_arr[index];
+
+ if (unlikely(buffer->skb == NULL)) {
+ WARN_ON(1);
+ return NULL;
+ }
+
+ pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
+ PCI_DMA_FROMDEVICE);
+
+ skb = buffer->skb;
+
+ if (likely((adapter->netdev->features & NETIF_F_RXCSUM) &&
+ (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
+ adapter->stats.csummed++;
+ skb->ip_summed = CHECKSUM_UNNECESSARY;
+ } else {
+ skb_checksum_none_assert(skb);
+ }
+
+ buffer->skb = NULL;
+
+ return skb;
+}
+
+static inline int
+qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb,
+ u16 *vlan_tag)
+{
+ struct ethhdr *eth_hdr;
+
+ if (!__vlan_get_tag(skb, vlan_tag)) {
+ eth_hdr = (struct ethhdr *) skb->data;
+ memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
+ skb_pull(skb, VLAN_HLEN);
+ }
+ if (!adapter->pvid)
+ return 0;
+
+ if (*vlan_tag == adapter->pvid) {
+ /* Outer vlan tag. Packet should follow non-vlan path */
+ *vlan_tag = 0xffff;
+ return 0;
+ }
+ if (adapter->flags & QLCNIC_TAGGING_ENABLED)
+ return 0;
+
+ return -EINVAL;
+}
+
+static struct qlcnic_rx_buffer *
+qlcnic_process_rcv(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_sds_ring *sds_ring,
+ int ring, u64 sts_data0)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+ struct qlcnic_rx_buffer *buffer;
+ struct sk_buff *skb;
+ struct qlcnic_host_rds_ring *rds_ring;
+ int index, length, cksum, pkt_offset;
+ u16 vid = 0xffff;
+
+ if (unlikely(ring >= adapter->max_rds_rings))
+ return NULL;
+
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ index = qlcnic_get_sts_refhandle(sts_data0);
+ if (unlikely(index >= rds_ring->num_desc))
+ return NULL;
+
+ buffer = &rds_ring->rx_buf_arr[index];
+
+ length = qlcnic_get_sts_totallength(sts_data0);
+ cksum = qlcnic_get_sts_status(sts_data0);
+ pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+ skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+ if (!skb)
+ return buffer;
+
+ if (length > rds_ring->skb_size)
+ skb_put(skb, rds_ring->skb_size);
+ else
+ skb_put(skb, length);
+
+ if (pkt_offset)
+ skb_pull(skb, pkt_offset);
+
+ if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+ adapter->stats.rxdropped++;
+ dev_kfree_skb(skb);
+ return buffer;
+ }
+
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ if (vid != 0xffff)
+ __vlan_hwaccel_put_tag(skb, vid);
+
+ napi_gro_receive(&sds_ring->napi, skb);
+
+ adapter->stats.rx_pkts++;
+ adapter->stats.rxbytes += length;
+
+ return buffer;
+}
+
+#define QLC_TCP_HDR_SIZE 20
+#define QLC_TCP_TS_OPTION_SIZE 12
+#define QLC_TCP_TS_HDR_SIZE (QLC_TCP_HDR_SIZE + QLC_TCP_TS_OPTION_SIZE)
+
+static struct qlcnic_rx_buffer *
+qlcnic_process_lro(struct qlcnic_adapter *adapter,
+ int ring, u64 sts_data0, u64 sts_data1)
+{
+ struct net_device *netdev = adapter->netdev;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+ struct qlcnic_rx_buffer *buffer;
+ struct sk_buff *skb;
+ struct qlcnic_host_rds_ring *rds_ring;
+ struct iphdr *iph;
+ struct tcphdr *th;
+ bool push, timestamp;
+ int l2_hdr_offset, l4_hdr_offset;
+ int index;
+ u16 lro_length, length, data_offset;
+ u32 seq_number;
+ u16 vid = 0xffff;
+
+ if (unlikely(ring > adapter->max_rds_rings))
+ return NULL;
+
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ index = qlcnic_get_lro_sts_refhandle(sts_data0);
+ if (unlikely(index > rds_ring->num_desc))
+ return NULL;
+
+ buffer = &rds_ring->rx_buf_arr[index];
+
+ timestamp = qlcnic_get_lro_sts_timestamp(sts_data0);
+ lro_length = qlcnic_get_lro_sts_length(sts_data0);
+ l2_hdr_offset = qlcnic_get_lro_sts_l2_hdr_offset(sts_data0);
+ l4_hdr_offset = qlcnic_get_lro_sts_l4_hdr_offset(sts_data0);
+ push = qlcnic_get_lro_sts_push_flag(sts_data0);
+ seq_number = qlcnic_get_lro_sts_seq_number(sts_data1);
+
+ skb = qlcnic_process_rxbuf(adapter, rds_ring, index, STATUS_CKSUM_OK);
+ if (!skb)
+ return buffer;
+
+ if (timestamp)
+ data_offset = l4_hdr_offset + QLC_TCP_TS_HDR_SIZE;
+ else
+ data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE;
+
+ skb_put(skb, lro_length + data_offset);
+
+ skb_pull(skb, l2_hdr_offset);
+
+ if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
+ adapter->stats.rxdropped++;
+ dev_kfree_skb(skb);
+ return buffer;
+ }
+
+ skb->protocol = eth_type_trans(skb, netdev);
+
+ iph = (struct iphdr *)skb->data;
+ th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
+
+ length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
+ iph->tot_len = htons(length);
+ iph->check = 0;
+ iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
+ th->psh = push;
+ th->seq = htonl(seq_number);
+
+ length = skb->len;
+
+ if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
+ skb_shinfo(skb)->gso_size = qlcnic_get_lro_sts_mss(sts_data1);
+
+ if (vid != 0xffff)
+ __vlan_hwaccel_put_tag(skb, vid);
+ netif_receive_skb(skb);
+
+ adapter->stats.lro_pkts++;
+ adapter->stats.lrobytes += length;
+
+ return buffer;
+}
+
+int
+qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
+{
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+ struct list_head *cur;
+ struct status_desc *desc;
+ struct qlcnic_rx_buffer *rxbuf;
+ u64 sts_data0, sts_data1;
+
+ int count = 0;
+ int opcode, ring, desc_cnt;
+ u32 consumer = sds_ring->consumer;
+
+ while (count < max) {
+ desc = &sds_ring->desc_head[consumer];
+ sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+ if (!(sts_data0 & STATUS_OWNER_HOST))
+ break;
+
+ desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+ opcode = qlcnic_get_sts_opcode(sts_data0);
+
+ switch (opcode) {
+ case QLCNIC_RXPKT_DESC:
+ case QLCNIC_OLD_RXPKT_DESC:
+ case QLCNIC_SYN_OFFLOAD:
+ ring = qlcnic_get_sts_type(sts_data0);
+ rxbuf = qlcnic_process_rcv(adapter, sds_ring,
+ ring, sts_data0);
+ break;
+ case QLCNIC_LRO_DESC:
+ ring = qlcnic_get_lro_sts_type(sts_data0);
+ sts_data1 = le64_to_cpu(desc->status_desc_data[1]);
+ rxbuf = qlcnic_process_lro(adapter, ring, sts_data0,
+ sts_data1);
+ break;
+ case QLCNIC_RESPONSE_DESC:
+ qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
+ default:
+ goto skip;
+ }
+
+ WARN_ON(desc_cnt > 1);
+
+ if (likely(rxbuf))
+ list_add_tail(&rxbuf->list, &sds_ring->free_list[ring]);
+ else
+ adapter->stats.null_rxbuf++;
+
+skip:
+ for (; desc_cnt > 0; desc_cnt--) {
+ desc = &sds_ring->desc_head[consumer];
+ desc->status_desc_data[0] =
+ cpu_to_le64(STATUS_OWNER_PHANTOM);
+ consumer = get_next_index(consumer, sds_ring->num_desc);
+ }
+ count++;
+ }
+
+ for (ring = 0; ring < adapter->max_rds_rings; ring++) {
+ struct qlcnic_host_rds_ring *rds_ring =
+ &adapter->recv_ctx->rds_rings[ring];
+
+ if (!list_empty(&sds_ring->free_list[ring])) {
+ list_for_each(cur, &sds_ring->free_list[ring]) {
+ rxbuf = list_entry(cur,
+ struct qlcnic_rx_buffer, list);
+ qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
+ }
+ spin_lock(&rds_ring->lock);
+ list_splice_tail_init(&sds_ring->free_list[ring],
+ &rds_ring->free_list);
+ spin_unlock(&rds_ring->lock);
+ }
+
+ qlcnic_post_rx_buffers_nodb(adapter, rds_ring);
+ }
+
+ if (count) {
+ sds_ring->consumer = consumer;
+ writel(consumer, sds_ring->crb_sts_consumer);
+ }
+
+ return count;
+}
+
+void
+qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring)
+{
+ struct rcv_desc *pdesc;
+ struct qlcnic_rx_buffer *buffer;
+ int count = 0;
+ u32 producer;
+ struct list_head *head;
+
+ producer = rds_ring->producer;
+
+ head = &rds_ring->free_list;
+ while (!list_empty(head)) {
+
+ buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
+
+ if (!buffer->skb) {
+ if (qlcnic_alloc_rx_skb(adapter, rds_ring, buffer))
+ break;
+ }
+
+ count++;
+ list_del(&buffer->list);
+
+ /* make a rcv descriptor */
+ pdesc = &rds_ring->desc_head[producer];
+ pdesc->addr_buffer = cpu_to_le64(buffer->dma);
+ pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
+ pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
+
+ producer = get_next_index(producer, rds_ring->num_desc);
+ }
+
+ if (count) {
+ rds_ring->producer = producer;
+ writel((producer-1) & (rds_ring->num_desc-1),
+ rds_ring->crb_rcv_producer);
+ }
+}
+
+static void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter)
+{
+ int i;
+ unsigned char *data = skb->data;
+
+ printk(KERN_INFO "\n");
+ for (i = 0; i < skb->len; i++) {
+ QLCDB(adapter, DRV, "%02x ", data[i]);
+ if ((i & 0x0f) == 8)
+ printk(KERN_INFO "\n");
+ }
+}
+
+static void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, int ring,
+ u64 sts_data0)
+{
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+ struct sk_buff *skb;
+ struct qlcnic_host_rds_ring *rds_ring;
+ int index, length, cksum, pkt_offset;
+
+ if (unlikely(ring >= adapter->max_rds_rings))
+ return;
+
+ rds_ring = &recv_ctx->rds_rings[ring];
+
+ index = qlcnic_get_sts_refhandle(sts_data0);
+ length = qlcnic_get_sts_totallength(sts_data0);
+ if (unlikely(index >= rds_ring->num_desc))
+ return;
+
+ cksum = qlcnic_get_sts_status(sts_data0);
+ pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
+
+ skb = qlcnic_process_rxbuf(adapter, rds_ring, index, cksum);
+ if (!skb)
+ return;
+
+ if (length > rds_ring->skb_size)
+ skb_put(skb, rds_ring->skb_size);
+ else
+ skb_put(skb, length);
+
+ if (pkt_offset)
+ skb_pull(skb, pkt_offset);
+
+ if (!qlcnic_check_loopback_buff(skb->data, adapter->mac_addr))
+ adapter->diag_cnt++;
+ else
+ dump_skb(skb, adapter);
+
+ dev_kfree_skb_any(skb);
+ adapter->stats.rx_pkts++;
+ adapter->stats.rxbytes += length;
+
+ return;
+}
+
+void
+qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+{
+ struct qlcnic_adapter *adapter = sds_ring->adapter;
+ struct status_desc *desc;
+ u64 sts_data0;
+ int ring, opcode, desc_cnt;
+
+ u32 consumer = sds_ring->consumer;
+
+ desc = &sds_ring->desc_head[consumer];
+ sts_data0 = le64_to_cpu(desc->status_desc_data[0]);
+
+ if (!(sts_data0 & STATUS_OWNER_HOST))
+ return;
+
+ desc_cnt = qlcnic_get_sts_desc_cnt(sts_data0);
+ opcode = qlcnic_get_sts_opcode(sts_data0);
+ switch (opcode) {
+ case QLCNIC_RESPONSE_DESC:
+ qlcnic_handle_fw_message(desc_cnt, consumer, sds_ring);
+ break;
+ default:
+ ring = qlcnic_get_sts_type(sts_data0);
+ qlcnic_process_rcv_diag(adapter, ring, sts_data0);
+ break;
+ }
+
+ for (; desc_cnt > 0; desc_cnt--) {
+ desc = &sds_ring->desc_head[consumer];
+ desc->status_desc_data[0] = cpu_to_le64(STATUS_OWNER_PHANTOM);
+ consumer = get_next_index(consumer, sds_ring->num_desc);
+ }
+
+ sds_ring->consumer = consumer;
+ writel(consumer, sds_ring->crb_sts_consumer);
+}
+
+void qlcnic_fetch_mac(u32 off1, u32 off2, u8 alt_mac, u8 *mac)
+{
+ u32 mac_low, mac_high;
+ int i;
+
+ mac_low = off1;
+ mac_high = off2;
+
+ if (alt_mac) {
+ mac_low |= (mac_low >> 16) | (mac_high << 16);
+ mac_high >>= 16;
+ }
+
+ for (i = 0; i < 2; i++)
+ mac[i] = (u8)(mac_high >> ((1 - i) * 8));
+ for (i = 2; i < 6; i++)
+ mac[i] = (u8)(mac_low >> ((5 - i) * 8));
+}
+
+int qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
+{
+ int ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+ if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
+ return -ENOMEM;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+
+ if (ring == adapter->max_sds_rings - 1)
+ netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
+ QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings);
+ else
+ netif_napi_add(netdev, &sds_ring->napi,
+ qlcnic_rx_poll, QLCNIC_NETDEV_WEIGHT*2);
+ }
+
+ return 0;
+}
+
+void qlcnic_napi_del(struct qlcnic_adapter *adapter)
+{
+ int ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ netif_napi_del(&sds_ring->napi);
+ }
+
+ qlcnic_free_sds_rings(adapter->recv_ctx);
+}
+
+void qlcnic_napi_enable(struct qlcnic_adapter *adapter)
+{
+ int ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ napi_enable(&sds_ring->napi);
+ qlcnic_enable_int(sds_ring);
+ }
+}
+
+void qlcnic_napi_disable(struct qlcnic_adapter *adapter)
+{
+ int ring;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
+
+ if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
+ return;
+
+ for (ring = 0; ring < adapter->max_sds_rings; ring++) {
+ sds_ring = &recv_ctx->sds_rings[ring];
+ qlcnic_disable_int(sds_ring);
+ napi_synchronize(&sds_ring->napi);
+ napi_disable(&sds_ring->napi);
+ }
+}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 67159d6..1d334e9 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -66,8 +66,6 @@ static void qlcnic_fw_poll_work(struct work_struct *work);
static void qlcnic_schedule_work(struct qlcnic_adapter *adapter,
work_func_t func, int delay);
static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
-static int qlcnic_poll(struct napi_struct *napi, int budget);
-static int qlcnic_rx_poll(struct napi_struct *napi, int budget);
#ifdef CONFIG_NET_POLL_CONTROLLER
static void qlcnic_poll_controller(struct net_device *netdev);
#endif
@@ -130,23 +128,7 @@ static const u32 msi_tgt_status[8] = {
static const
struct qlcnic_legacy_intr_set legacy_intr[] = QLCNIC_LEGACY_INTR_CONFIG;
-static inline void qlcnic_disable_int(struct qlcnic_host_sds_ring *sds_ring)
-{
- writel(0, sds_ring->crb_intr_mask);
-}
-
-static inline void qlcnic_enable_int(struct qlcnic_host_sds_ring *sds_ring)
-{
- struct qlcnic_adapter *adapter = sds_ring->adapter;
-
- writel(0x1, sds_ring->crb_intr_mask);
-
- if (!QLCNIC_IS_MSI_FAMILY(adapter))
- writel(0xfbff, adapter->tgt_mask_reg);
-}
-
-static int
-qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
+int qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
{
int size = sizeof(struct qlcnic_host_sds_ring) * count;
@@ -155,8 +137,7 @@ qlcnic_alloc_sds_rings(struct qlcnic_recv_context *recv_ctx, int count)
return recv_ctx->sds_rings == NULL;
}
-static void
-qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
+void qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
{
if (recv_ctx->sds_rings != NULL)
kfree(recv_ctx->sds_rings);
@@ -164,80 +145,6 @@ qlcnic_free_sds_rings(struct qlcnic_recv_context *recv_ctx)
recv_ctx->sds_rings = NULL;
}
-static int
-qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
-{
- int ring;
- struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
-
- if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
- return -ENOMEM;
-
- for (ring = 0; ring < adapter->max_sds_rings; ring++) {
- sds_ring = &recv_ctx->sds_rings[ring];
-
- if (ring == adapter->max_sds_rings - 1)
- netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
- QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings);
- else
- netif_napi_add(netdev, &sds_ring->napi,
- qlcnic_rx_poll, QLCNIC_NETDEV_WEIGHT*2);
- }
-
- return 0;
-}
-
-static void
-qlcnic_napi_del(struct qlcnic_adapter *adapter)
-{
- int ring;
- struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
-
- for (ring = 0; ring < adapter->max_sds_rings; ring++) {
- sds_ring = &recv_ctx->sds_rings[ring];
- netif_napi_del(&sds_ring->napi);
- }
-
- qlcnic_free_sds_rings(adapter->recv_ctx);
-}
-
-static void
-qlcnic_napi_enable(struct qlcnic_adapter *adapter)
-{
- int ring;
- struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
-
- if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
- return;
-
- for (ring = 0; ring < adapter->max_sds_rings; ring++) {
- sds_ring = &recv_ctx->sds_rings[ring];
- napi_enable(&sds_ring->napi);
- qlcnic_enable_int(sds_ring);
- }
-}
-
-static void
-qlcnic_napi_disable(struct qlcnic_adapter *adapter)
-{
- int ring;
- struct qlcnic_host_sds_ring *sds_ring;
- struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
-
- if (adapter->is_up != QLCNIC_ADAPTER_UP_MAGIC)
- return;
-
- for (ring = 0; ring < adapter->max_sds_rings; ring++) {
- sds_ring = &recv_ctx->sds_rings[ring];
- qlcnic_disable_int(sds_ring);
- napi_synchronize(&sds_ring->napi);
- napi_disable(&sds_ring->napi);
- }
-}
-
static void qlcnic_clear_stats(struct qlcnic_adapter *adapter)
{
memset(&adapter->stats, 0, sizeof(adapter->stats));
@@ -1924,428 +1831,6 @@ static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
adapter->fhash.fmax = 0;
}
-static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
- u64 uaddr, __le16 vlan_id, struct qlcnic_host_tx_ring *tx_ring)
-{
- struct cmd_desc_type0 *hwdesc;
- struct qlcnic_nic_req *req;
- struct qlcnic_mac_req *mac_req;
- struct qlcnic_vlan_req *vlan_req;
- u32 producer;
- u64 word;
-
- producer = tx_ring->producer;
- hwdesc = &tx_ring->desc_head[tx_ring->producer];
-
- req = (struct qlcnic_nic_req *)hwdesc;
- memset(req, 0, sizeof(struct qlcnic_nic_req));
- req->qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
-
- word = QLCNIC_MAC_EVENT | ((u64)(adapter->portnum) << 16);
- req->req_hdr = cpu_to_le64(word);
-
- mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
- mac_req->op = vlan_id ? QLCNIC_MAC_VLAN_ADD : QLCNIC_MAC_ADD;
- memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
-
- vlan_req = (struct qlcnic_vlan_req *)&req->words[1];
- vlan_req->vlan_id = vlan_id;
-
- tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
- smp_mb();
-}
-
-#define QLCNIC_MAC_HASH(MAC)\
- ((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
-
-static void
-qlcnic_send_filter(struct qlcnic_adapter *adapter,
- struct qlcnic_host_tx_ring *tx_ring,
- struct cmd_desc_type0 *first_desc,
- struct sk_buff *skb)
-{
- struct ethhdr *phdr = (struct ethhdr *)(skb->data);
- struct qlcnic_filter *fil, *tmp_fil;
- struct hlist_node *tmp_hnode, *n;
- struct hlist_head *head;
- u64 src_addr = 0;
- __le16 vlan_id = 0;
- u8 hindex;
-
- if (ether_addr_equal(phdr->h_source, adapter->mac_addr))
- return;
-
- if (adapter->fhash.fnum >= adapter->fhash.fmax)
- return;
-
- /* Only NPAR capable devices support vlan based learning*/
- if (adapter->flags & QLCNIC_ESWITCH_ENABLED)
- vlan_id = first_desc->vlan_TCI;
- memcpy(&src_addr, phdr->h_source, ETH_ALEN);
- hindex = QLCNIC_MAC_HASH(src_addr) & (QLCNIC_LB_MAX_FILTERS - 1);
- head = &(adapter->fhash.fhead[hindex]);
-
- hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
- if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
- tmp_fil->vlan_id == vlan_id) {
-
- if (jiffies >
- (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
- qlcnic_change_filter(adapter, src_addr, vlan_id,
- tx_ring);
- tmp_fil->ftime = jiffies;
- return;
- }
- }
-
- fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
- if (!fil)
- return;
-
- qlcnic_change_filter(adapter, src_addr, vlan_id, tx_ring);
-
- fil->ftime = jiffies;
- fil->vlan_id = vlan_id;
- memcpy(fil->faddr, &src_addr, ETH_ALEN);
- spin_lock(&adapter->mac_learn_lock);
- hlist_add_head(&(fil->fnode), head);
- adapter->fhash.fnum++;
- spin_unlock(&adapter->mac_learn_lock);
-}
-
-static int
-qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
- struct cmd_desc_type0 *first_desc,
- struct sk_buff *skb)
-{
- u8 opcode = 0, hdr_len = 0;
- u16 flags = 0, vlan_tci = 0;
- int copied, offset, copy_len;
- struct cmd_desc_type0 *hwdesc;
- struct vlan_ethhdr *vh;
- struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
- u16 protocol = ntohs(skb->protocol);
- u32 producer = tx_ring->producer;
-
- if (protocol == ETH_P_8021Q) {
- vh = (struct vlan_ethhdr *)skb->data;
- flags = FLAGS_VLAN_TAGGED;
- vlan_tci = ntohs(vh->h_vlan_TCI);
- protocol = ntohs(vh->h_vlan_encapsulated_proto);
- } else if (vlan_tx_tag_present(skb)) {
- flags = FLAGS_VLAN_OOB;
- vlan_tci = vlan_tx_tag_get(skb);
- }
- if (unlikely(adapter->pvid)) {
- if (vlan_tci && !(adapter->flags & QLCNIC_TAGGING_ENABLED))
- return -EIO;
- if (vlan_tci && (adapter->flags & QLCNIC_TAGGING_ENABLED))
- goto set_flags;
-
- flags = FLAGS_VLAN_OOB;
- vlan_tci = adapter->pvid;
- }
-set_flags:
- qlcnic_set_tx_vlan_tci(first_desc, vlan_tci);
- qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
-
- if (*(skb->data) & BIT_0) {
- flags |= BIT_0;
- memcpy(&first_desc->eth_addr, skb->data, ETH_ALEN);
- }
- opcode = TX_ETHER_PKT;
- if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
- skb_shinfo(skb)->gso_size > 0) {
-
- hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
-
- first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
- first_desc->total_hdr_length = hdr_len;
-
- opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO;
-
- /* For LSO, we need to copy the MAC/IP/TCP headers into
- * the descriptor ring */
- copied = 0;
- offset = 2;
-
- if (flags & FLAGS_VLAN_OOB) {
- first_desc->total_hdr_length += VLAN_HLEN;
- first_desc->tcp_hdr_offset = VLAN_HLEN;
- first_desc->ip_hdr_offset = VLAN_HLEN;
- /* Only in case of TSO on vlan device */
- flags |= FLAGS_VLAN_TAGGED;
-
- /* Create a TSO vlan header template for firmware */
-
- hwdesc = &tx_ring->desc_head[producer];
- tx_ring->cmd_buf_arr[producer].skb = NULL;
-
- copy_len = min((int)sizeof(struct cmd_desc_type0) -
- offset, hdr_len + VLAN_HLEN);
-
- vh = (struct vlan_ethhdr *)((char *) hwdesc + 2);
- skb_copy_from_linear_data(skb, vh, 12);
- vh->h_vlan_proto = htons(ETH_P_8021Q);
- vh->h_vlan_TCI = htons(vlan_tci);
-
- skb_copy_from_linear_data_offset(skb, 12,
- (char *)vh + 16, copy_len - 16);
-
- copied = copy_len - VLAN_HLEN;
- offset = 0;
-
- producer = get_next_index(producer, tx_ring->num_desc);
- }
-
- while (copied < hdr_len) {
-
- copy_len = min((int)sizeof(struct cmd_desc_type0) -
- offset, (hdr_len - copied));
-
- hwdesc = &tx_ring->desc_head[producer];
- tx_ring->cmd_buf_arr[producer].skb = NULL;
-
- skb_copy_from_linear_data_offset(skb, copied,
- (char *) hwdesc + offset, copy_len);
-
- copied += copy_len;
- offset = 0;
-
- producer = get_next_index(producer, tx_ring->num_desc);
- }
-
- tx_ring->producer = producer;
- smp_mb();
- adapter->stats.lso_frames++;
-
- } else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- u8 l4proto;
-
- if (protocol == ETH_P_IP) {
- l4proto = ip_hdr(skb)->protocol;
-
- if (l4proto == IPPROTO_TCP)
- opcode = TX_TCP_PKT;
- else if (l4proto == IPPROTO_UDP)
- opcode = TX_UDP_PKT;
- } else if (protocol == ETH_P_IPV6) {
- l4proto = ipv6_hdr(skb)->nexthdr;
-
- if (l4proto == IPPROTO_TCP)
- opcode = TX_TCPV6_PKT;
- else if (l4proto == IPPROTO_UDP)
- opcode = TX_UDPV6_PKT;
- }
- }
- first_desc->tcp_hdr_offset += skb_transport_offset(skb);
- first_desc->ip_hdr_offset += skb_network_offset(skb);
- qlcnic_set_tx_flags_opcode(first_desc, flags, opcode);
-
- return 0;
-}
-
-static int
-qlcnic_map_tx_skb(struct pci_dev *pdev,
- struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
-{
- struct qlcnic_skb_frag *nf;
- struct skb_frag_struct *frag;
- int i, nr_frags;
- dma_addr_t map;
-
- nr_frags = skb_shinfo(skb)->nr_frags;
- nf = &pbuf->frag_array[0];
-
- map = pci_map_single(pdev, skb->data,
- skb_headlen(skb), PCI_DMA_TODEVICE);
- if (pci_dma_mapping_error(pdev, map))
- goto out_err;
-
- nf->dma = map;
- nf->length = skb_headlen(skb);
-
- for (i = 0; i < nr_frags; i++) {
- frag = &skb_shinfo(skb)->frags[i];
- nf = &pbuf->frag_array[i+1];
-
- map = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
- DMA_TO_DEVICE);
- if (dma_mapping_error(&pdev->dev, map))
- goto unwind;
-
- nf->dma = map;
- nf->length = skb_frag_size(frag);
- }
-
- return 0;
-
-unwind:
- while (--i >= 0) {
- nf = &pbuf->frag_array[i+1];
- pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
- }
-
- nf = &pbuf->frag_array[0];
- pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
-
-out_err:
- return -ENOMEM;
-}
-
-static void
-qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb,
- struct qlcnic_cmd_buffer *pbuf)
-{
- struct qlcnic_skb_frag *nf = &pbuf->frag_array[0];
- int nr_frags = skb_shinfo(skb)->nr_frags;
- int i;
-
- for (i = 0; i < nr_frags; i++) {
- nf = &pbuf->frag_array[i+1];
- pci_unmap_page(pdev, nf->dma, nf->length, PCI_DMA_TODEVICE);
- }
-
- nf = &pbuf->frag_array[0];
- pci_unmap_single(pdev, nf->dma, skb_headlen(skb), PCI_DMA_TODEVICE);
- pbuf->skb = NULL;
-}
-
-static inline void
-qlcnic_clear_cmddesc(u64 *desc)
-{
- desc[0] = 0ULL;
- desc[2] = 0ULL;
- desc[7] = 0ULL;
-}
-
-netdev_tx_t
-qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
-{
- struct qlcnic_adapter *adapter = netdev_priv(netdev);
- struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
- struct qlcnic_cmd_buffer *pbuf;
- struct qlcnic_skb_frag *buffrag;
- struct cmd_desc_type0 *hwdesc, *first_desc;
- struct pci_dev *pdev;
- struct ethhdr *phdr;
- int delta = 0;
- int i, k;
-
- u32 producer;
- int frag_count;
- u32 num_txd = tx_ring->num_desc;
-
- if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
- netif_stop_queue(netdev);
- return NETDEV_TX_BUSY;
- }
-
- if (adapter->flags & QLCNIC_MACSPOOF) {
- phdr = (struct ethhdr *)skb->data;
- if (!ether_addr_equal(phdr->h_source, adapter->mac_addr))
- goto drop_packet;
- }
-
- frag_count = skb_shinfo(skb)->nr_frags + 1;
- /* 14 frags supported for normal packet and
- * 32 frags supported for TSO packet
- */
- if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) {
-
- for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++)
- delta += skb_frag_size(&skb_shinfo(skb)->frags[i]);
-
- if (!__pskb_pull_tail(skb, delta))
- goto drop_packet;
-
- frag_count = 1 + skb_shinfo(skb)->nr_frags;
- }
-
- if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
- netif_stop_queue(netdev);
- if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
- netif_start_queue(netdev);
- else {
- adapter->stats.xmit_off++;
- return NETDEV_TX_BUSY;
- }
- }
-
- producer = tx_ring->producer;
- pbuf = &tx_ring->cmd_buf_arr[producer];
-
- pdev = adapter->pdev;
-
- first_desc = hwdesc = &tx_ring->desc_head[producer];
- qlcnic_clear_cmddesc((u64 *)hwdesc);
-
- if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
- adapter->stats.tx_dma_map_error++;
- goto drop_packet;
- }
-
- pbuf->skb = skb;
- pbuf->frag_count = frag_count;
-
- qlcnic_set_tx_frags_len(first_desc, frag_count, skb->len);
- qlcnic_set_tx_port(first_desc, adapter->portnum);
-
- for (i = 0; i < frag_count; i++) {
-
- k = i % 4;
-
- if ((k == 0) && (i > 0)) {
- /* move to next desc.*/
- producer = get_next_index(producer, num_txd);
- hwdesc = &tx_ring->desc_head[producer];
- qlcnic_clear_cmddesc((u64 *)hwdesc);
- tx_ring->cmd_buf_arr[producer].skb = NULL;
- }
-
- buffrag = &pbuf->frag_array[i];
-
- hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
- switch (k) {
- case 0:
- hwdesc->addr_buffer1 = cpu_to_le64(buffrag->dma);
- break;
- case 1:
- hwdesc->addr_buffer2 = cpu_to_le64(buffrag->dma);
- break;
- case 2:
- hwdesc->addr_buffer3 = cpu_to_le64(buffrag->dma);
- break;
- case 3:
- hwdesc->addr_buffer4 = cpu_to_le64(buffrag->dma);
- break;
- }
- }
-
- tx_ring->producer = get_next_index(producer, num_txd);
- smp_mb();
-
- if (unlikely(qlcnic_tx_pkt(adapter, first_desc, skb)))
- goto unwind_buff;
-
- if (adapter->mac_learn)
- qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
-
- adapter->stats.txbytes += skb->len;
- adapter->stats.xmitcalled++;
-
- qlcnic_update_cmd_producer(tx_ring);
-
- return NETDEV_TX_OK;
-
-unwind_buff:
- qlcnic_unmap_buffers(pdev, skb, pbuf);
-drop_packet:
- adapter->stats.txdropped++;
- dev_kfree_skb_any(skb);
- return NETDEV_TX_OK;
-}
-
static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
{
struct net_device *netdev = adapter->netdev;
@@ -2382,27 +1867,6 @@ static int qlcnic_check_temp(struct qlcnic_adapter *adapter)
return rv;
}
-void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
-{
- struct net_device *netdev = adapter->netdev;
-
- if (adapter->ahw->linkup && !linkup) {
- netdev_info(netdev, "NIC Link is down\n");
- adapter->ahw->linkup = 0;
- if (netif_running(netdev)) {
- netif_carrier_off(netdev);
- netif_stop_queue(netdev);
- }
- } else if (!adapter->ahw->linkup && linkup) {
- netdev_info(netdev, "NIC Link is up\n");
- adapter->ahw->linkup = 1;
- if (netif_running(netdev)) {
- netif_carrier_on(netdev);
- netif_wake_queue(netdev);
- }
- }
-}
-
static void qlcnic_tx_timeout(struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
@@ -2509,122 +1973,6 @@ static irqreturn_t qlcnic_msix_intr(int irq, void *data)
return IRQ_HANDLED;
}
-static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
-{
- u32 sw_consumer, hw_consumer;
- int count = 0, i;
- struct qlcnic_cmd_buffer *buffer;
- struct pci_dev *pdev = adapter->pdev;
- struct net_device *netdev = adapter->netdev;
- struct qlcnic_skb_frag *frag;
- int done;
- struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
-
- if (!spin_trylock(&adapter->tx_clean_lock))
- return 1;
-
- sw_consumer = tx_ring->sw_consumer;
- hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
-
- while (sw_consumer != hw_consumer) {
- buffer = &tx_ring->cmd_buf_arr[sw_consumer];
- if (buffer->skb) {
- frag = &buffer->frag_array[0];
- pci_unmap_single(pdev, frag->dma, frag->length,
- PCI_DMA_TODEVICE);
- frag->dma = 0ULL;
- for (i = 1; i < buffer->frag_count; i++) {
- frag++;
- pci_unmap_page(pdev, frag->dma, frag->length,
- PCI_DMA_TODEVICE);
- frag->dma = 0ULL;
- }
-
- adapter->stats.xmitfinished++;
- dev_kfree_skb_any(buffer->skb);
- buffer->skb = NULL;
- }
-
- sw_consumer = get_next_index(sw_consumer, tx_ring->num_desc);
- if (++count >= MAX_STATUS_HANDLE)
- break;
- }
-
- if (count && netif_running(netdev)) {
- tx_ring->sw_consumer = sw_consumer;
-
- smp_mb();
-
- if (netif_queue_stopped(netdev) && netif_carrier_ok(netdev)) {
- if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
- netif_wake_queue(netdev);
- adapter->stats.xmit_on++;
- }
- }
- adapter->tx_timeo_cnt = 0;
- }
- /*
- * If everything is freed up to consumer then check if the ring is full
- * If the ring is full then check if more needs to be freed and
- * schedule the call back again.
- *
- * This happens when there are 2 CPUs. One could be freeing and the
- * other filling it. If the ring is full when we get out of here and
- * the card has already interrupted the host then the host can miss the
- * interrupt.
- *
- * There is still a possible race condition and the host could miss an
- * interrupt. The card has to take care of this.
- */
- hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
- done = (sw_consumer == hw_consumer);
- spin_unlock(&adapter->tx_clean_lock);
-
- return done;
-}
-
-static int qlcnic_poll(struct napi_struct *napi, int budget)
-{
- struct qlcnic_host_sds_ring *sds_ring =
- container_of(napi, struct qlcnic_host_sds_ring, napi);
-
- struct qlcnic_adapter *adapter = sds_ring->adapter;
-
- int tx_complete;
- int work_done;
-
- tx_complete = qlcnic_process_cmd_ring(adapter);
-
- work_done = qlcnic_process_rcv_ring(sds_ring, budget);
-
- if ((work_done < budget) && tx_complete) {
- napi_complete(&sds_ring->napi);
- if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
- qlcnic_enable_int(sds_ring);
- }
-
- return work_done;
-}
-
-static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
-{
- struct qlcnic_host_sds_ring *sds_ring =
- container_of(napi, struct qlcnic_host_sds_ring, napi);
-
- struct qlcnic_adapter *adapter = sds_ring->adapter;
- int work_done;
-
- work_done = qlcnic_process_rcv_ring(sds_ring, budget);
-
- if (work_done < budget) {
- napi_complete(&sds_ring->napi);
- if (test_bit(__QLCNIC_DEV_UP, &adapter->state))
- qlcnic_enable_int(sds_ring);
- }
-
- return work_done;
-}
-
#ifdef CONFIG_NET_POLL_CONTROLLER
static void qlcnic_poll_controller(struct net_device *netdev)
{
--
1.7.1
^ permalink raw reply related
* [PATCH 0/6] qlcnic: refactor 82xx adapter driver
From: Sony Chacko @ 2012-11-28 14:34 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
From: Sony Chacko <sony.chacko@qlogic.com>
Refactor 82xx adapter driver to create new files for:
Data path routines.
Sysfs interface routines.
Hardware register dump utility.
We are refactoring the driver code to add support for a new adapter.
Existing 82xx driver code has coding style issues.
Each physical refactoring patch is followed by a seperate patch
to fix the style issues in the newly created file.
Patches in the series are listed below.
0001-qlcnic-create-file-qlcnic_io.c-for-datapath-routines.patch
0002-qlcnic-fix-coding-style-issues-in-qlcnic_io.c.patch
0003-qlcnic-create-file-qlcnic_sysfs.c-for-sysfs-routines.patch
0004-qlcnic-fix-style-issues-in-qlcnic_sysfs.c-file.patch
0005-qlcnic-create-file-qlcnic_minidump.c-for-dump-utilit.patch
0006-qlcnic-fix-coding-style-issues-in-qlcnic_minidump.c.patch
Please apply to net-next.
Thanks,
Sony
^ permalink raw reply
* [PATCH 4/6] qlcnic: fix style issues in qlcnic_sysfs.c file
From: Sony Chacko @ 2012-11-28 14:34 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
In-Reply-To: <1354113271-23850-1-git-send-email-sony.chacko@qlogic.com>
From: Sony Chacko <sony.chacko@qlogic.com>
Fix coding style issues in qlcnic_sysfs.c file
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 243 +++++++++++----------
1 files changed, 127 insertions(+), 116 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
index e2bad8b..10a702a 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -25,9 +25,9 @@ int qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
return -EOPNOTSUPP;
}
-static ssize_t
-qlcnic_store_bridged_mode(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
+static ssize_t qlcnic_store_bridged_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
unsigned long new;
@@ -49,9 +49,9 @@ err_out:
return ret;
}
-static ssize_t
-qlcnic_show_bridged_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t qlcnic_show_bridged_mode(struct device *dev,
+ struct device_attribute *attr,
+ char *buf)
{
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
int bridged_mode = 0;
@@ -62,9 +62,9 @@ qlcnic_show_bridged_mode(struct device *dev,
return sprintf(buf, "%d\n", bridged_mode);
}
-static ssize_t
-qlcnic_store_diag_mode(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
+static ssize_t qlcnic_store_diag_mode(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
unsigned long new;
@@ -78,19 +78,17 @@ qlcnic_store_diag_mode(struct device *dev,
return len;
}
-static ssize_t
-qlcnic_show_diag_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t qlcnic_show_diag_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
return sprintf(buf, "%d\n",
- !!(adapter->flags & QLCNIC_DIAG_ENABLED));
+ !!(adapter->flags & QLCNIC_DIAG_ENABLED));
}
-static int
-qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon, u8 *state,
- u8 *rate)
+static int qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon,
+ u8 *state, u8 *rate)
{
*rate = LSB(beacon);
*state = MSB(beacon);
@@ -100,8 +98,9 @@ qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon, u8 *state,
if (!*state) {
*rate = __QLCNIC_MAX_LED_RATE;
return 0;
- } else if (*state > __QLCNIC_MAX_LED_STATE)
+ } else if (*state > __QLCNIC_MAX_LED_STATE) {
return -EINVAL;
+ }
if ((!*rate) || (*rate > __QLCNIC_MAX_LED_RATE))
return -EINVAL;
@@ -109,9 +108,9 @@ qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon, u8 *state,
return 0;
}
-static ssize_t
-qlcnic_store_beacon(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
+static ssize_t qlcnic_store_beacon(struct device *dev,
+ struct device_attribute *attr,
+ const char *buf, size_t len)
{
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
int max_sds_rings = adapter->max_sds_rings;
@@ -120,8 +119,8 @@ qlcnic_store_beacon(struct device *dev,
int err;
if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
- dev_warn(dev, "LED test not supported for non "
- "privilege function\n");
+ dev_warn(dev,
+ "LED test not supported in non privileged mode\n");
return -EOPNOTSUPP;
}
@@ -174,18 +173,16 @@ qlcnic_store_beacon(struct device *dev,
return err;
}
-static ssize_t
-qlcnic_show_beacon(struct device *dev,
- struct device_attribute *attr, char *buf)
+static ssize_t qlcnic_show_beacon(struct device *dev,
+ struct device_attribute *attr, char *buf)
{
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
return sprintf(buf, "%d\n", adapter->ahw->beacon_state);
}
-static int
-qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
- loff_t offset, size_t size)
+static int qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
+ loff_t offset, size_t size)
{
size_t crb_size = 4;
@@ -194,7 +191,7 @@ qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
if (offset < QLCNIC_PCI_CRBSPACE) {
if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
- QLCNIC_PCI_CAMQM_END))
+ QLCNIC_PCI_CAMQM_END))
crb_size = 8;
else
return -EINVAL;
@@ -206,10 +203,9 @@ qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
return 0;
}
-static ssize_t
-qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t offset, size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -231,10 +227,9 @@ qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
return size;
}
-static ssize_t
-qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t offset, size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -256,9 +251,8 @@ qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
return size;
}
-static int
-qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
- loff_t offset, size_t size)
+static int qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
+ loff_t offset, size_t size)
{
if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
return -EIO;
@@ -269,10 +263,9 @@ qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
return 0;
}
-static ssize_t
-qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t offset, size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -291,10 +284,9 @@ qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
return size;
}
-static ssize_t
-qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf,
+ loff_t offset, size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -313,20 +305,17 @@ qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
return size;
}
-static int
-validate_pm_config(struct qlcnic_adapter *adapter,
- struct qlcnic_pm_func_cfg *pm_cfg, int count)
+static int validate_pm_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_pm_func_cfg *pm_cfg, int count)
{
-
- u8 src_pci_func, s_esw_id, d_esw_id;
- u8 dest_pci_func;
+ u8 src_pci_func, s_esw_id, d_esw_id, dest_pci_func;
int i;
for (i = 0; i < count; i++) {
src_pci_func = pm_cfg[i].pci_func;
dest_pci_func = pm_cfg[i].dest_npar;
- if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
- || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
+ if (src_pci_func >= QLCNIC_MAX_PCI_FUNC ||
+ dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
return QL_STATUS_INVALID_PARAM;
if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
@@ -340,15 +329,16 @@ validate_pm_config(struct qlcnic_adapter *adapter,
if (s_esw_id != d_esw_id)
return QL_STATUS_INVALID_PARAM;
-
}
return 0;
}
-static ssize_t
-qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_write_pm_config(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -361,7 +351,7 @@ qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
if (rem)
return QL_STATUS_INVALID_PARAM;
- pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
+ pm_cfg = (struct qlcnic_pm_func_cfg *)buf;
ret = validate_pm_config(adapter, pm_cfg, count);
if (ret)
@@ -370,8 +360,8 @@ qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
pci_func = pm_cfg[i].pci_func;
action = !!pm_cfg[i].action;
id = adapter->npars[pci_func].phy_port;
- ret = qlcnic_config_port_mirroring(adapter, id,
- action, pci_func);
+ ret = qlcnic_config_port_mirroring(adapter, id, action,
+ pci_func);
if (ret)
return ret;
}
@@ -385,9 +375,11 @@ qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
return size;
}
-static ssize_t
-qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_read_pm_config(struct file *filp,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -409,9 +401,8 @@ qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
return size;
}
-static int
-validate_esw_config(struct qlcnic_adapter *adapter,
- struct qlcnic_esw_func_cfg *esw_cfg, int count)
+static int validate_esw_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg, int count)
{
u32 op_mode;
u8 pci_func;
@@ -424,14 +415,15 @@ validate_esw_config(struct qlcnic_adapter *adapter,
if (pci_func >= QLCNIC_MAX_PCI_FUNC)
return QL_STATUS_INVALID_PARAM;
- if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+ if (adapter->op_mode == QLCNIC_MGMT_FUNC) {
if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
return QL_STATUS_INVALID_PARAM;
+ }
switch (esw_cfg[i].op_mode) {
case QLCNIC_PORT_DEFAULTS:
if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
- QLCNIC_NON_PRIV_FUNC) {
+ QLCNIC_NON_PRIV_FUNC) {
if (esw_cfg[i].mac_anti_spoof != 0)
return QL_STATUS_INVALID_PARAM;
if (esw_cfg[i].mac_override != 1)
@@ -457,9 +449,11 @@ validate_esw_config(struct qlcnic_adapter *adapter,
return 0;
}
-static ssize_t
-qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_write_esw_config(struct file *file,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -473,15 +467,16 @@ qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
if (rem)
return QL_STATUS_INVALID_PARAM;
- esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
+ esw_cfg = (struct qlcnic_esw_func_cfg *)buf;
ret = validate_esw_config(adapter, esw_cfg, count);
if (ret)
return ret;
for (i = 0; i < count; i++) {
- if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+ if (adapter->op_mode == QLCNIC_MGMT_FUNC) {
if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
return QL_STATUS_INVALID_PARAM;
+ }
if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
continue;
@@ -531,9 +526,11 @@ out:
return size;
}
-static ssize_t
-qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_read_esw_config(struct file *file,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -555,9 +552,9 @@ qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
return size;
}
-static int
-validate_npar_config(struct qlcnic_adapter *adapter,
- struct qlcnic_npar_func_cfg *np_cfg, int count)
+static int validate_npar_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_npar_func_cfg *np_cfg,
+ int count)
{
u8 pci_func, i;
@@ -576,9 +573,11 @@ validate_npar_config(struct qlcnic_adapter *adapter,
return 0;
}
-static ssize_t
-qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_write_npar_config(struct file *file,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -592,7 +591,7 @@ qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
if (rem)
return QL_STATUS_INVALID_PARAM;
- np_cfg = (struct qlcnic_npar_func_cfg *) buf;
+ np_cfg = (struct qlcnic_npar_func_cfg *)buf;
ret = validate_npar_config(adapter, np_cfg, count);
if (ret)
return ret;
@@ -615,9 +614,12 @@ qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
return size;
}
-static ssize_t
-qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+
+static ssize_t qlcnic_sysfs_read_npar_config(struct file *file,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -628,7 +630,7 @@ qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
if (size != sizeof(np_cfg))
return QL_STATUS_INVALID_PARAM;
- for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
continue;
ret = qlcnic_get_nic_info(adapter, &nic_info, i);
@@ -639,7 +641,7 @@ qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
np_cfg[i].op_mode = (u8)nic_info.op_mode;
np_cfg[i].port_num = nic_info.phys_port;
np_cfg[i].fw_capab = nic_info.capabilities;
- np_cfg[i].min_bw = nic_info.min_tx_bw ;
+ np_cfg[i].min_bw = nic_info.min_tx_bw;
np_cfg[i].max_bw = nic_info.max_tx_bw;
np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
@@ -648,9 +650,11 @@ qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
return size;
}
-static ssize_t
-qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_get_port_stats(struct file *file,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -665,12 +669,12 @@ qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
memset(&port_stats, 0, size);
ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
- &port_stats.rx);
+ &port_stats.rx);
if (ret)
return ret;
ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
- &port_stats.tx);
+ &port_stats.tx);
if (ret)
return ret;
@@ -678,9 +682,11 @@ qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
return size;
}
-static ssize_t
-qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_get_esw_stats(struct file *file,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -695,12 +701,12 @@ qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
memset(&esw_stats, 0, size);
ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
- &esw_stats.rx);
+ &esw_stats.rx);
if (ret)
return ret;
ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
- &esw_stats.tx);
+ &esw_stats.tx);
if (ret)
return ret;
@@ -708,9 +714,11 @@ qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
return size;
}
-static ssize_t
-qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_clear_esw_stats(struct file *file,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -720,23 +728,24 @@ qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj,
return QL_STATUS_INVALID_PARAM;
ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
- QLCNIC_QUERY_RX_COUNTER);
+ QLCNIC_QUERY_RX_COUNTER);
if (ret)
return ret;
ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
- QLCNIC_QUERY_TX_COUNTER);
+ QLCNIC_QUERY_TX_COUNTER);
if (ret)
return ret;
return size;
}
-static ssize_t
-qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_clear_port_stats(struct file *file,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
-
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
int ret;
@@ -745,21 +754,23 @@ qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj,
return QL_STATUS_INVALID_PARAM;
ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
- QLCNIC_QUERY_RX_COUNTER);
+ QLCNIC_QUERY_RX_COUNTER);
if (ret)
return ret;
ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
- QLCNIC_QUERY_TX_COUNTER);
+ QLCNIC_QUERY_TX_COUNTER);
if (ret)
return ret;
return size;
}
-static ssize_t
-qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+static ssize_t qlcnic_sysfs_read_pci_config(struct file *file,
+ struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset,
+ size_t size)
{
struct device *dev = container_of(kobj, struct device, kobj);
struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
@@ -874,7 +885,7 @@ void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
if (device_create_file(dev, &dev_attr_bridged_mode))
dev_warn(dev,
- "failed to create bridged_mode sysfs entry\n");
+ "failed to create bridged_mode sysfs entry\n");
}
void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
--
1.7.1
^ permalink raw reply related
* [PATCH 2/6] qlcnic: fix coding style issues in qlcnic_io.c
From: Sony Chacko @ 2012-11-28 14:34 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
In-Reply-To: <1354113271-23850-1-git-send-email-sony.chacko@qlogic.com>
From: Sony Chacko <sony.chacko@qlogic.com>
Fix coding style issues in qlcnic_io.c
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c | 263 +++++++++++--------------
1 file changed, 113 insertions(+), 150 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
index 25e6ffc..ba352c1 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_io.c
@@ -94,8 +94,10 @@
/* for status field in status_desc */
#define STATUS_CKSUM_LOOP 0
#define STATUS_CKSUM_OK 2
+
static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
- u64 uaddr, __le16 vlan_id, struct qlcnic_host_tx_ring *tx_ring)
+ u64 uaddr, __le16 vlan_id,
+ struct qlcnic_host_tx_ring *tx_ring)
{
struct cmd_desc_type0 *hwdesc;
struct qlcnic_nic_req *req;
@@ -125,11 +127,10 @@ static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
smp_mb();
}
-static void
-qlcnic_send_filter(struct qlcnic_adapter *adapter,
- struct qlcnic_host_tx_ring *tx_ring,
- struct cmd_desc_type0 *first_desc,
- struct sk_buff *skb)
+static void qlcnic_send_filter(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_tx_ring *tx_ring,
+ struct cmd_desc_type0 *first_desc,
+ struct sk_buff *skb)
{
struct ethhdr *phdr = (struct ethhdr *)(skb->data);
struct qlcnic_filter *fil, *tmp_fil;
@@ -156,10 +157,9 @@ qlcnic_send_filter(struct qlcnic_adapter *adapter,
if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN) &&
tmp_fil->vlan_id == vlan_id) {
- if (jiffies >
- (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
+ if (jiffies > (QLCNIC_READD_AGE * HZ + tmp_fil->ftime))
qlcnic_change_filter(adapter, src_addr, vlan_id,
- tx_ring);
+ tx_ring);
tmp_fil->ftime = jiffies;
return;
}
@@ -174,20 +174,21 @@ qlcnic_send_filter(struct qlcnic_adapter *adapter,
fil->ftime = jiffies;
fil->vlan_id = vlan_id;
memcpy(fil->faddr, &src_addr, ETH_ALEN);
+
spin_lock(&adapter->mac_learn_lock);
+
hlist_add_head(&(fil->fnode), head);
adapter->fhash.fnum++;
+
spin_unlock(&adapter->mac_learn_lock);
}
-static int
-qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
- struct cmd_desc_type0 *first_desc,
- struct sk_buff *skb)
+static int qlcnic_tx_pkt(struct qlcnic_adapter *adapter,
+ struct cmd_desc_type0 *first_desc, struct sk_buff *skb)
{
- u8 opcode = 0, hdr_len = 0;
+ u8 l4proto, opcode = 0, hdr_len = 0;
u16 flags = 0, vlan_tci = 0;
- int copied, offset, copy_len;
+ int copied, offset, copy_len, size;
struct cmd_desc_type0 *hwdesc;
struct vlan_ethhdr *vh;
struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
@@ -222,13 +223,10 @@ set_flags:
}
opcode = TX_ETHER_PKT;
if ((adapter->netdev->features & (NETIF_F_TSO | NETIF_F_TSO6)) &&
- skb_shinfo(skb)->gso_size > 0) {
-
+ skb_shinfo(skb)->gso_size > 0) {
hdr_len = skb_transport_offset(skb) + tcp_hdrlen(skb);
-
first_desc->mss = cpu_to_le16(skb_shinfo(skb)->gso_size);
first_desc->total_hdr_length = hdr_len;
-
opcode = (protocol == ETH_P_IPV6) ? TX_TCP_LSO6 : TX_TCP_LSO;
/* For LSO, we need to copy the MAC/IP/TCP headers into
@@ -240,16 +238,16 @@ set_flags:
first_desc->total_hdr_length += VLAN_HLEN;
first_desc->tcp_hdr_offset = VLAN_HLEN;
first_desc->ip_hdr_offset = VLAN_HLEN;
+
/* Only in case of TSO on vlan device */
flags |= FLAGS_VLAN_TAGGED;
/* Create a TSO vlan header template for firmware */
-
hwdesc = &tx_ring->desc_head[producer];
tx_ring->cmd_buf_arr[producer].skb = NULL;
copy_len = min((int)sizeof(struct cmd_desc_type0) -
- offset, hdr_len + VLAN_HLEN);
+ offset, hdr_len + VLAN_HLEN);
vh = (struct vlan_ethhdr *)((char *) hwdesc + 2);
skb_copy_from_linear_data(skb, vh, 12);
@@ -257,28 +255,23 @@ set_flags:
vh->h_vlan_TCI = htons(vlan_tci);
skb_copy_from_linear_data_offset(skb, 12,
- (char *)vh + 16, copy_len - 16);
-
+ (char *)vh + 16,
+ copy_len - 16);
copied = copy_len - VLAN_HLEN;
offset = 0;
-
producer = get_next_index(producer, tx_ring->num_desc);
}
while (copied < hdr_len) {
-
- copy_len = min((int)sizeof(struct cmd_desc_type0) -
- offset, (hdr_len - copied));
-
+ size = (int)sizeof(struct cmd_desc_type0) - offset;
+ copy_len = min(size, (hdr_len - copied));
hwdesc = &tx_ring->desc_head[producer];
tx_ring->cmd_buf_arr[producer].skb = NULL;
-
skb_copy_from_linear_data_offset(skb, copied,
- (char *) hwdesc + offset, copy_len);
-
+ (char *)hwdesc +
+ offset, copy_len);
copied += copy_len;
offset = 0;
-
producer = get_next_index(producer, tx_ring->num_desc);
}
@@ -287,8 +280,6 @@ set_flags:
adapter->stats.lso_frames++;
} else if (skb->ip_summed == CHECKSUM_PARTIAL) {
- u8 l4proto;
-
if (protocol == ETH_P_IP) {
l4proto = ip_hdr(skb)->protocol;
@@ -312,9 +303,8 @@ set_flags:
return 0;
}
-static int
-qlcnic_map_tx_skb(struct pci_dev *pdev,
- struct sk_buff *skb, struct qlcnic_cmd_buffer *pbuf)
+static int qlcnic_map_tx_skb(struct pci_dev *pdev, struct sk_buff *skb,
+ struct qlcnic_cmd_buffer *pbuf)
{
struct qlcnic_skb_frag *nf;
struct skb_frag_struct *frag;
@@ -324,8 +314,8 @@ qlcnic_map_tx_skb(struct pci_dev *pdev,
nr_frags = skb_shinfo(skb)->nr_frags;
nf = &pbuf->frag_array[0];
- map = pci_map_single(pdev, skb->data,
- skb_headlen(skb), PCI_DMA_TODEVICE);
+ map = pci_map_single(pdev, skb->data, skb_headlen(skb),
+ PCI_DMA_TODEVICE);
if (pci_dma_mapping_error(pdev, map))
goto out_err;
@@ -335,7 +325,6 @@ qlcnic_map_tx_skb(struct pci_dev *pdev,
for (i = 0; i < nr_frags; i++) {
frag = &skb_shinfo(skb)->frags[i];
nf = &pbuf->frag_array[i+1];
-
map = skb_frag_dma_map(&pdev->dev, frag, 0, skb_frag_size(frag),
DMA_TO_DEVICE);
if (dma_mapping_error(&pdev->dev, map))
@@ -360,13 +349,11 @@ out_err:
return -ENOMEM;
}
-static void
-qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb,
- struct qlcnic_cmd_buffer *pbuf)
+static void qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb,
+ struct qlcnic_cmd_buffer *pbuf)
{
struct qlcnic_skb_frag *nf = &pbuf->frag_array[0];
- int nr_frags = skb_shinfo(skb)->nr_frags;
- int i;
+ int i, nr_frags = skb_shinfo(skb)->nr_frags;
for (i = 0; i < nr_frags; i++) {
nf = &pbuf->frag_array[i+1];
@@ -378,16 +365,14 @@ qlcnic_unmap_buffers(struct pci_dev *pdev, struct sk_buff *skb,
pbuf->skb = NULL;
}
-static inline void
-qlcnic_clear_cmddesc(u64 *desc)
+static inline void qlcnic_clear_cmddesc(u64 *desc)
{
desc[0] = 0ULL;
desc[2] = 0ULL;
desc[7] = 0ULL;
}
-netdev_tx_t
-qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
+netdev_tx_t qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
{
struct qlcnic_adapter *adapter = netdev_priv(netdev);
struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
@@ -396,12 +381,10 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
struct cmd_desc_type0 *hwdesc, *first_desc;
struct pci_dev *pdev;
struct ethhdr *phdr;
- int delta = 0;
- int i, k;
+ int i, k, frag_count, delta = 0;
+ u32 producer, num_txd;
- u32 producer;
- int frag_count;
- u32 num_txd = tx_ring->num_desc;
+ num_txd = tx_ring->num_desc;
if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
netif_stop_queue(netdev);
@@ -419,7 +402,6 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
* 32 frags supported for TSO packet
*/
if (!skb_is_gso(skb) && frag_count > QLCNIC_MAX_FRAGS_PER_TX) {
-
for (i = 0; i < (frag_count - QLCNIC_MAX_FRAGS_PER_TX); i++)
delta += skb_frag_size(&skb_shinfo(skb)->frags[i]);
@@ -431,9 +413,9 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
if (unlikely(qlcnic_tx_avail(tx_ring) <= TX_STOP_THRESH)) {
netif_stop_queue(netdev);
- if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH)
+ if (qlcnic_tx_avail(tx_ring) > TX_STOP_THRESH) {
netif_start_queue(netdev);
- else {
+ } else {
adapter->stats.xmit_off++;
return NETDEV_TX_BUSY;
}
@@ -441,10 +423,9 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
producer = tx_ring->producer;
pbuf = &tx_ring->cmd_buf_arr[producer];
-
pdev = adapter->pdev;
-
- first_desc = hwdesc = &tx_ring->desc_head[producer];
+ first_desc = &tx_ring->desc_head[producer];
+ hwdesc = &tx_ring->desc_head[producer];
qlcnic_clear_cmddesc((u64 *)hwdesc);
if (qlcnic_map_tx_skb(pdev, skb, pbuf)) {
@@ -459,7 +440,6 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
qlcnic_set_tx_port(first_desc, adapter->portnum);
for (i = 0; i < frag_count; i++) {
-
k = i % 4;
if ((k == 0) && (i > 0)) {
@@ -471,7 +451,6 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
}
buffrag = &pbuf->frag_array[i];
-
hwdesc->buffer_length[k] = cpu_to_le16(buffrag->length);
switch (k) {
case 0:
@@ -534,10 +513,9 @@ void qlcnic_advert_link_change(struct qlcnic_adapter *adapter, int linkup)
}
}
-static int
-qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring,
- struct qlcnic_rx_buffer *buffer)
+static int qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring,
+ struct qlcnic_rx_buffer *buffer)
{
struct sk_buff *skb;
dma_addr_t dma;
@@ -550,9 +528,8 @@ qlcnic_alloc_rx_skb(struct qlcnic_adapter *adapter,
}
skb_reserve(skb, NET_IP_ALIGN);
-
- dma = pci_map_single(pdev, skb->data,
- rds_ring->dma_size, PCI_DMA_FROMDEVICE);
+ dma = pci_map_single(pdev, skb->data, rds_ring->dma_size,
+ PCI_DMA_FROMDEVICE);
if (pci_dma_mapping_error(pdev, dma)) {
adapter->stats.rx_dma_map_error++;
@@ -579,10 +556,9 @@ static void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
return;
producer = rds_ring->producer;
-
head = &rds_ring->free_list;
- while (!list_empty(head)) {
+ while (!list_empty(head)) {
buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
if (!buffer->skb) {
@@ -598,27 +574,26 @@ static void qlcnic_post_rx_buffers_nodb(struct qlcnic_adapter *adapter,
pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
pdesc->addr_buffer = cpu_to_le64(buffer->dma);
-
producer = get_next_index(producer, rds_ring->num_desc);
}
if (count) {
rds_ring->producer = producer;
writel((producer - 1) & (rds_ring->num_desc - 1),
- rds_ring->crb_rcv_producer);
+ rds_ring->crb_rcv_producer);
}
+
spin_unlock(&rds_ring->lock);
}
static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
{
u32 sw_consumer, hw_consumer;
- int count = 0, i;
+ int i, done, count = 0;
struct qlcnic_cmd_buffer *buffer;
struct pci_dev *pdev = adapter->pdev;
struct net_device *netdev = adapter->netdev;
struct qlcnic_skb_frag *frag;
- int done;
struct qlcnic_host_tx_ring *tx_ring = adapter->tx_ring;
if (!spin_trylock(&adapter->tx_clean_lock))
@@ -679,6 +654,7 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
*/
hw_consumer = le32_to_cpu(*(tx_ring->hw_consumer));
done = (sw_consumer == hw_consumer);
+
spin_unlock(&adapter->tx_clean_lock);
return done;
@@ -686,16 +662,14 @@ static int qlcnic_process_cmd_ring(struct qlcnic_adapter *adapter)
static int qlcnic_poll(struct napi_struct *napi, int budget)
{
- struct qlcnic_host_sds_ring *sds_ring =
- container_of(napi, struct qlcnic_host_sds_ring, napi);
-
- struct qlcnic_adapter *adapter = sds_ring->adapter;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_adapter *adapter;
+ int tx_complete, work_done;
- int tx_complete;
- int work_done;
+ sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
+ adapter = sds_ring->adapter;
tx_complete = qlcnic_process_cmd_ring(adapter);
-
work_done = qlcnic_process_rcv_ring(sds_ring, budget);
if ((work_done < budget) && tx_complete) {
@@ -709,12 +683,13 @@ static int qlcnic_poll(struct napi_struct *napi, int budget)
static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
{
- struct qlcnic_host_sds_ring *sds_ring =
- container_of(napi, struct qlcnic_host_sds_ring, napi);
-
- struct qlcnic_adapter *adapter = sds_ring->adapter;
+ struct qlcnic_host_sds_ring *sds_ring;
+ struct qlcnic_adapter *adapter;
int work_done;
+ sds_ring = container_of(napi, struct qlcnic_host_sds_ring, napi);
+ adapter = sds_ring->adapter;
+
work_done = qlcnic_process_rcv_ring(sds_ring, budget);
if (work_done < budget) {
@@ -726,15 +701,12 @@ static int qlcnic_rx_poll(struct napi_struct *napi, int budget)
return work_done;
}
-static void
-qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
- struct qlcnic_fw_msg *msg)
+static void qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
+ struct qlcnic_fw_msg *msg)
{
u32 cable_OUI;
- u16 cable_len;
- u16 link_speed;
- u8 link_status, module, duplex, autoneg;
- u8 lb_status = 0;
+ u16 cable_len, link_speed;
+ u8 link_status, module, duplex, autoneg, lb_status = 0;
struct net_device *netdev = adapter->netdev;
adapter->has_link_events = 1;
@@ -750,11 +722,12 @@ qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
module = (msg->body[2] >> 8) & 0xff;
if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLE)
- dev_info(&netdev->dev, "unsupported cable: OUI 0x%x, "
- "length %d\n", cable_OUI, cable_len);
+ dev_info(&netdev->dev,
+ "unsupported cable: OUI 0x%x, length %d\n",
+ cable_OUI, cable_len);
else if (module == LINKEVENT_MODULE_TWINAX_UNSUPPORTED_CABLELEN)
dev_info(&netdev->dev, "unsupported cable length %d\n",
- cable_len);
+ cable_len);
if (!link_status && (lb_status == QLCNIC_ILB_MODE ||
lb_status == QLCNIC_ELB_MODE))
@@ -778,9 +751,8 @@ qlcnic_handle_linkevent(struct qlcnic_adapter *adapter,
}
}
-static void
-qlcnic_handle_fw_message(int desc_cnt, int index,
- struct qlcnic_host_sds_ring *sds_ring)
+static void qlcnic_handle_fw_message(int desc_cnt, int index,
+ struct qlcnic_host_sds_ring *sds_ring)
{
struct qlcnic_fw_msg msg;
struct status_desc *desc;
@@ -820,8 +792,9 @@ qlcnic_handle_fw_message(int desc_cnt, int index,
adapter->diag_cnt = -QLCNIC_LB_CABLE_NOT_CONN;
break;
default:
- dev_info(dev, "loopback configure request failed,"
- " ret %x\n", ret);
+ dev_info(dev,
+ "loopback configure request failed, err %x\n",
+ ret);
adapter->diag_cnt = -QLCNIC_UNDEFINED_ERROR;
break;
}
@@ -831,8 +804,10 @@ qlcnic_handle_fw_message(int desc_cnt, int index,
}
}
-static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring, u16 index, u16 cksum)
+static struct sk_buff *
+qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring, u16 index,
+ u16 cksum)
{
struct qlcnic_rx_buffer *buffer;
struct sk_buff *skb;
@@ -845,12 +820,12 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
}
pci_unmap_single(adapter->pdev, buffer->dma, rds_ring->dma_size,
- PCI_DMA_FROMDEVICE);
+ PCI_DMA_FROMDEVICE);
skb = buffer->skb;
if (likely((adapter->netdev->features & NETIF_F_RXCSUM) &&
- (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
+ (cksum == STATUS_CKSUM_OK || cksum == STATUS_CKSUM_LOOP))) {
adapter->stats.csummed++;
skb->ip_summed = CHECKSUM_UNNECESSARY;
} else {
@@ -862,14 +837,13 @@ static struct sk_buff *qlcnic_process_rxbuf(struct qlcnic_adapter *adapter,
return skb;
}
-static inline int
-qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb,
- u16 *vlan_tag)
+static inline int qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter,
+ struct sk_buff *skb, u16 *vlan_tag)
{
struct ethhdr *eth_hdr;
if (!__vlan_get_tag(skb, vlan_tag)) {
- eth_hdr = (struct ethhdr *) skb->data;
+ eth_hdr = (struct ethhdr *)skb->data;
memmove(skb->data + VLAN_HLEN, eth_hdr, ETH_ALEN * 2);
skb_pull(skb, VLAN_HLEN);
}
@@ -889,8 +863,8 @@ qlcnic_check_rx_tagging(struct qlcnic_adapter *adapter, struct sk_buff *skb,
static struct qlcnic_rx_buffer *
qlcnic_process_rcv(struct qlcnic_adapter *adapter,
- struct qlcnic_host_sds_ring *sds_ring,
- int ring, u64 sts_data0)
+ struct qlcnic_host_sds_ring *sds_ring, int ring,
+ u64 sts_data0)
{
struct net_device *netdev = adapter->netdev;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
@@ -910,7 +884,6 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
return NULL;
buffer = &rds_ring->rx_buf_arr[index];
-
length = qlcnic_get_sts_totallength(sts_data0);
cksum = qlcnic_get_sts_status(sts_data0);
pkt_offset = qlcnic_get_sts_pkt_offset(sts_data0);
@@ -952,7 +925,7 @@ qlcnic_process_rcv(struct qlcnic_adapter *adapter,
static struct qlcnic_rx_buffer *
qlcnic_process_lro(struct qlcnic_adapter *adapter,
- int ring, u64 sts_data0, u64 sts_data1)
+ int ring, u64 sts_data0, u64 sts_data1)
{
struct net_device *netdev = adapter->netdev;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
@@ -962,11 +935,9 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
struct iphdr *iph;
struct tcphdr *th;
bool push, timestamp;
- int l2_hdr_offset, l4_hdr_offset;
- int index;
- u16 lro_length, length, data_offset;
+ int index, l2_hdr_offset, l4_hdr_offset;
+ u16 lro_length, length, data_offset, vid = 0xffff;
u32 seq_number;
- u16 vid = 0xffff;
if (unlikely(ring > adapter->max_rds_rings))
return NULL;
@@ -996,7 +967,6 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
data_offset = l4_hdr_offset + QLC_TCP_HDR_SIZE;
skb_put(skb, lro_length + data_offset);
-
skb_pull(skb, l2_hdr_offset);
if (unlikely(qlcnic_check_rx_tagging(adapter, skb, &vid))) {
@@ -1006,17 +976,14 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
}
skb->protocol = eth_type_trans(skb, netdev);
-
iph = (struct iphdr *)skb->data;
th = (struct tcphdr *)(skb->data + (iph->ihl << 2));
-
length = (iph->ihl << 2) + (th->doff << 2) + lro_length;
iph->tot_len = htons(length);
iph->check = 0;
iph->check = ip_fast_csum((unsigned char *)iph, iph->ihl);
th->psh = push;
th->seq = htonl(seq_number);
-
length = skb->len;
if (adapter->flags & QLCNIC_FW_LRO_MSS_CAP)
@@ -1032,17 +999,16 @@ qlcnic_process_lro(struct qlcnic_adapter *adapter,
return buffer;
}
-int
-qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
+int qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
{
+ struct qlcnic_host_rds_ring *rds_ring;
struct qlcnic_adapter *adapter = sds_ring->adapter;
struct list_head *cur;
struct status_desc *desc;
struct qlcnic_rx_buffer *rxbuf;
u64 sts_data0, sts_data1;
-
- int count = 0;
- int opcode, ring, desc_cnt;
+ __le64 owner_phantom = cpu_to_le64(STATUS_OWNER_PHANTOM);
+ int opcode, ring, desc_cnt, count = 0;
u32 consumer = sds_ring->consumer;
while (count < max) {
@@ -1060,8 +1026,8 @@ qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
case QLCNIC_OLD_RXPKT_DESC:
case QLCNIC_SYN_OFFLOAD:
ring = qlcnic_get_sts_type(sts_data0);
- rxbuf = qlcnic_process_rcv(adapter, sds_ring,
- ring, sts_data0);
+ rxbuf = qlcnic_process_rcv(adapter, sds_ring, ring,
+ sts_data0);
break;
case QLCNIC_LRO_DESC:
ring = qlcnic_get_lro_sts_type(sts_data0);
@@ -1085,26 +1051,24 @@ qlcnic_process_rcv_ring(struct qlcnic_host_sds_ring *sds_ring, int max)
skip:
for (; desc_cnt > 0; desc_cnt--) {
desc = &sds_ring->desc_head[consumer];
- desc->status_desc_data[0] =
- cpu_to_le64(STATUS_OWNER_PHANTOM);
+ desc->status_desc_data[0] = owner_phantom;
consumer = get_next_index(consumer, sds_ring->num_desc);
}
count++;
}
for (ring = 0; ring < adapter->max_rds_rings; ring++) {
- struct qlcnic_host_rds_ring *rds_ring =
- &adapter->recv_ctx->rds_rings[ring];
+ rds_ring = &adapter->recv_ctx->rds_rings[ring];
if (!list_empty(&sds_ring->free_list[ring])) {
list_for_each(cur, &sds_ring->free_list[ring]) {
- rxbuf = list_entry(cur,
- struct qlcnic_rx_buffer, list);
+ rxbuf = list_entry(cur, struct qlcnic_rx_buffer,
+ list);
qlcnic_alloc_rx_skb(adapter, rds_ring, rxbuf);
}
spin_lock(&rds_ring->lock);
list_splice_tail_init(&sds_ring->free_list[ring],
- &rds_ring->free_list);
+ &rds_ring->free_list);
spin_unlock(&rds_ring->lock);
}
@@ -1119,9 +1083,8 @@ skip:
return count;
}
-void
-qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
- struct qlcnic_host_rds_ring *rds_ring)
+void qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
+ struct qlcnic_host_rds_ring *rds_ring)
{
struct rcv_desc *pdesc;
struct qlcnic_rx_buffer *buffer;
@@ -1130,8 +1093,8 @@ qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
struct list_head *head;
producer = rds_ring->producer;
-
head = &rds_ring->free_list;
+
while (!list_empty(head)) {
buffer = list_entry(head->next, struct qlcnic_rx_buffer, list);
@@ -1149,14 +1112,13 @@ qlcnic_post_rx_buffers(struct qlcnic_adapter *adapter,
pdesc->addr_buffer = cpu_to_le64(buffer->dma);
pdesc->reference_handle = cpu_to_le16(buffer->ref_handle);
pdesc->buffer_length = cpu_to_le32(rds_ring->dma_size);
-
producer = get_next_index(producer, rds_ring->num_desc);
}
if (count) {
rds_ring->producer = producer;
writel((producer-1) & (rds_ring->num_desc-1),
- rds_ring->crb_rcv_producer);
+ rds_ring->crb_rcv_producer);
}
}
@@ -1165,11 +1127,11 @@ static void dump_skb(struct sk_buff *skb, struct qlcnic_adapter *adapter)
int i;
unsigned char *data = skb->data;
- printk(KERN_INFO "\n");
+ pr_info(KERN_INFO "\n");
for (i = 0; i < skb->len; i++) {
QLCDB(adapter, DRV, "%02x ", data[i]);
if ((i & 0x0f) == 8)
- printk(KERN_INFO "\n");
+ pr_info(KERN_INFO "\n");
}
}
@@ -1218,8 +1180,7 @@ static void qlcnic_process_rcv_diag(struct qlcnic_adapter *adapter, int ring,
return;
}
-void
-qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
+void qlcnic_process_rcv_ring_diag(struct qlcnic_host_sds_ring *sds_ring)
{
struct qlcnic_adapter *adapter = sds_ring->adapter;
struct status_desc *desc;
@@ -1277,22 +1238,24 @@ void qlcnic_fetch_mac(u32 off1, u32 off2, u8 alt_mac, u8 *mac)
int qlcnic_napi_add(struct qlcnic_adapter *adapter, struct net_device *netdev)
{
- int ring;
+ int ring, max_sds_rings;
struct qlcnic_host_sds_ring *sds_ring;
struct qlcnic_recv_context *recv_ctx = adapter->recv_ctx;
if (qlcnic_alloc_sds_rings(recv_ctx, adapter->max_sds_rings))
return -ENOMEM;
+ max_sds_rings = adapter->max_sds_rings;
+
for (ring = 0; ring < adapter->max_sds_rings; ring++) {
sds_ring = &recv_ctx->sds_rings[ring];
- if (ring == adapter->max_sds_rings - 1)
+ if (ring == max_sds_rings - 1)
netif_napi_add(netdev, &sds_ring->napi, qlcnic_poll,
- QLCNIC_NETDEV_WEIGHT/adapter->max_sds_rings);
+ QLCNIC_NETDEV_WEIGHT / max_sds_rings);
else
- netif_napi_add(netdev, &sds_ring->napi,
- qlcnic_rx_poll, QLCNIC_NETDEV_WEIGHT*2);
+ netif_napi_add(netdev, &sds_ring->napi, qlcnic_rx_poll,
+ QLCNIC_NETDEV_WEIGHT*2);
}
return 0;
--
1.8.0
^ permalink raw reply related
* [PATCH 3/6] qlcnic: create file qlcnic_sysfs.c for sysfs routines
From: Sony Chacko @ 2012-11-28 14:34 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
In-Reply-To: <1354113271-23850-1-git-send-email-sony.chacko@qlogic.com>
From: Sony Chacko <sony.chacko@qlogic.com>
Physical refactoring of 82xx adapter sysfs routines.
Move sysfs routines to new file qlcnic_sysfs.c
Existing sysfs routines has coding style issues, this code is
moved to the new file without fixing the style issues.
There is a seperate patch to fix the style issues in qlcnic_sysfs.c
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/Makefile | 3 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 11 +
drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c | 960 +--------------------
drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c | 951 ++++++++++++++++++++
4 files changed, 969 insertions(+), 956 deletions(-)
create mode 100644 drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
diff --git a/drivers/net/ethernet/qlogic/qlcnic/Makefile b/drivers/net/ethernet/qlogic/qlcnic/Makefile
index a26ee17..34db053 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/Makefile
+++ b/drivers/net/ethernet/qlogic/qlcnic/Makefile
@@ -5,4 +5,5 @@
obj-$(CONFIG_QLCNIC) := qlcnic.o
qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
- qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o
+ qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \
+ qlcnic_sysfs.o
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index db4508f..618e5ec 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1566,6 +1566,17 @@ void qlcnic_free_sds_rings(struct qlcnic_recv_context *);
void qlcnic_free_tx_rings(struct qlcnic_adapter *);
int qlcnic_alloc_tx_rings(struct qlcnic_adapter *, struct net_device *);
+void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);
+void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
+void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
+void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
+int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
+int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
+void qlcnic_set_vlan_config(struct qlcnic_adapter *,
+ struct qlcnic_esw_func_cfg *);
+void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *,
+ struct qlcnic_esw_func_cfg *);
+
/*
* QLOGIC Board information
*/
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
index 1d334e9..1eef0bf 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_main.c
@@ -70,11 +70,6 @@ static void qlcnic_cancel_fw_work(struct qlcnic_adapter *adapter);
static void qlcnic_poll_controller(struct net_device *netdev);
#endif
-static void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter);
-static void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter);
-static void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter);
-static void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter);
-
static void qlcnic_idc_debug_info(struct qlcnic_adapter *adapter, u8 encoding);
static void qlcnic_clr_all_drv_state(struct qlcnic_adapter *adapter, u8);
static int qlcnic_can_start_firmware(struct qlcnic_adapter *adapter);
@@ -90,8 +85,6 @@ static int qlcnic_start_firmware(struct qlcnic_adapter *);
static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
-static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
-static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
static int qlcnicvf_start_firmware(struct qlcnic_adapter *);
static void qlcnic_set_netdev_features(struct qlcnic_adapter *,
struct qlcnic_esw_func_cfg *);
@@ -629,9 +622,8 @@ qlcnic_initialize_nic(struct qlcnic_adapter *adapter)
return err;
}
-static void
-qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
- struct qlcnic_esw_func_cfg *esw_cfg)
+void qlcnic_set_vlan_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg)
{
if (esw_cfg->discard_tagged)
adapter->flags &= ~QLCNIC_TAGGING_ENABLED;
@@ -662,9 +654,8 @@ qlcnic_vlan_rx_del(struct net_device *netdev, u16 vid)
return 0;
}
-static void
-qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
- struct qlcnic_esw_func_cfg *esw_cfg)
+void qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg)
{
adapter->flags &= ~(QLCNIC_MACSPOOF | QLCNIC_MAC_OVERRIDE_DISABLED |
QLCNIC_PROMISC_DISABLED);
@@ -681,8 +672,7 @@ qlcnic_set_eswitch_port_features(struct qlcnic_adapter *adapter,
qlcnic_set_netdev_features(adapter, esw_cfg);
}
-static int
-qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
+static int qlcnic_set_eswitch_port_config(struct qlcnic_adapter *adapter)
{
struct qlcnic_esw_func_cfg esw_cfg;
@@ -2740,93 +2730,6 @@ qlcnicvf_start_firmware(struct qlcnic_adapter *adapter)
return err;
}
-static int
-qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
-{
- return -EOPNOTSUPP;
-}
-
-static int
-qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
-{
- return -EOPNOTSUPP;
-}
-
-static ssize_t
-qlcnic_store_bridged_mode(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
-{
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- unsigned long new;
- int ret = -EINVAL;
-
- if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
- goto err_out;
-
- if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
- goto err_out;
-
- if (strict_strtoul(buf, 2, &new))
- goto err_out;
-
- if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
- ret = len;
-
-err_out:
- return ret;
-}
-
-static ssize_t
-qlcnic_show_bridged_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- int bridged_mode = 0;
-
- if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
- bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
-
- return sprintf(buf, "%d\n", bridged_mode);
-}
-
-static struct device_attribute dev_attr_bridged_mode = {
- .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
- .show = qlcnic_show_bridged_mode,
- .store = qlcnic_store_bridged_mode,
-};
-
-static ssize_t
-qlcnic_store_diag_mode(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
-{
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- unsigned long new;
-
- if (strict_strtoul(buf, 2, &new))
- return -EINVAL;
-
- if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
- adapter->flags ^= QLCNIC_DIAG_ENABLED;
-
- return len;
-}
-
-static ssize_t
-qlcnic_show_diag_mode(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-
- return sprintf(buf, "%d\n",
- !!(adapter->flags & QLCNIC_DIAG_ENABLED));
-}
-
-static struct device_attribute dev_attr_diag_mode = {
- .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
- .show = qlcnic_show_diag_mode,
- .store = qlcnic_store_diag_mode,
-};
-
int qlcnic_validate_max_rss(struct net_device *netdev, u8 max_hw, u8 val)
{
if (!use_msi_x && !use_msi) {
@@ -2877,859 +2780,6 @@ int qlcnic_set_max_rss(struct qlcnic_adapter *adapter, u8 data)
return err;
}
-static int
-qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon, u8 *state,
- u8 *rate)
-{
- *rate = LSB(beacon);
- *state = MSB(beacon);
-
- QLCDB(adapter, DRV, "rate %x state %x\n", *rate, *state);
-
- if (!*state) {
- *rate = __QLCNIC_MAX_LED_RATE;
- return 0;
- } else if (*state > __QLCNIC_MAX_LED_STATE)
- return -EINVAL;
-
- if ((!*rate) || (*rate > __QLCNIC_MAX_LED_RATE))
- return -EINVAL;
-
- return 0;
-}
-
-static ssize_t
-qlcnic_store_beacon(struct device *dev,
- struct device_attribute *attr, const char *buf, size_t len)
-{
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- int max_sds_rings = adapter->max_sds_rings;
- u16 beacon;
- u8 b_state, b_rate;
- int err;
-
- if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
- dev_warn(dev, "LED test not supported for non "
- "privilege function\n");
- return -EOPNOTSUPP;
- }
-
- if (len != sizeof(u16))
- return QL_STATUS_INVALID_PARAM;
-
- memcpy(&beacon, buf, sizeof(u16));
- err = qlcnic_validate_beacon(adapter, beacon, &b_state, &b_rate);
- if (err)
- return err;
-
- if (adapter->ahw->beacon_state == b_state)
- return len;
-
- rtnl_lock();
-
- if (!adapter->ahw->beacon_state)
- if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
- rtnl_unlock();
- return -EBUSY;
- }
-
- if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
- err = -EIO;
- goto out;
- }
-
- if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
- err = qlcnic_diag_alloc_res(adapter->netdev, QLCNIC_LED_TEST);
- if (err)
- goto out;
- set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
- }
-
- err = qlcnic_config_led(adapter, b_state, b_rate);
-
- if (!err) {
- err = len;
- adapter->ahw->beacon_state = b_state;
- }
-
- if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
- qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
-
- out:
- if (!adapter->ahw->beacon_state)
- clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
- rtnl_unlock();
-
- return err;
-}
-
-static ssize_t
-qlcnic_show_beacon(struct device *dev,
- struct device_attribute *attr, char *buf)
-{
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
-
- return sprintf(buf, "%d\n", adapter->ahw->beacon_state);
-}
-
-static struct device_attribute dev_attr_beacon = {
- .attr = {.name = "beacon", .mode = (S_IRUGO | S_IWUSR)},
- .show = qlcnic_show_beacon,
- .store = qlcnic_store_beacon,
-};
-
-static int
-qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
- loff_t offset, size_t size)
-{
- size_t crb_size = 4;
-
- if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
- return -EIO;
-
- if (offset < QLCNIC_PCI_CRBSPACE) {
- if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
- QLCNIC_PCI_CAMQM_END))
- crb_size = 8;
- else
- return -EINVAL;
- }
-
- if ((size != crb_size) || (offset & (crb_size-1)))
- return -EINVAL;
-
- return 0;
-}
-
-static ssize_t
-qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u32 data;
- u64 qmdata;
- int ret;
-
- ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
- if (ret != 0)
- return ret;
-
- if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
- qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
- memcpy(buf, &qmdata, size);
- } else {
- data = QLCRD32(adapter, offset);
- memcpy(buf, &data, size);
- }
- return size;
-}
-
-static ssize_t
-qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u32 data;
- u64 qmdata;
- int ret;
-
- ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
- if (ret != 0)
- return ret;
-
- if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
- memcpy(&qmdata, buf, size);
- qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
- } else {
- memcpy(&data, buf, size);
- QLCWR32(adapter, offset, data);
- }
- return size;
-}
-
-static int
-qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
- loff_t offset, size_t size)
-{
- if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
- return -EIO;
-
- if ((size != 8) || (offset & 0x7))
- return -EIO;
-
- return 0;
-}
-
-static ssize_t
-qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u64 data;
- int ret;
-
- ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
- if (ret != 0)
- return ret;
-
- if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
- return -EIO;
-
- memcpy(buf, &data, size);
-
- return size;
-}
-
-static ssize_t
-qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr,
- char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- u64 data;
- int ret;
-
- ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
- if (ret != 0)
- return ret;
-
- memcpy(&data, buf, size);
-
- if (qlcnic_pci_mem_write_2M(adapter, offset, data))
- return -EIO;
-
- return size;
-}
-
-static struct bin_attribute bin_attr_crb = {
- .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
- .size = 0,
- .read = qlcnic_sysfs_read_crb,
- .write = qlcnic_sysfs_write_crb,
-};
-
-static struct bin_attribute bin_attr_mem = {
- .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
- .size = 0,
- .read = qlcnic_sysfs_read_mem,
- .write = qlcnic_sysfs_write_mem,
-};
-
-static int
-validate_pm_config(struct qlcnic_adapter *adapter,
- struct qlcnic_pm_func_cfg *pm_cfg, int count)
-{
-
- u8 src_pci_func, s_esw_id, d_esw_id;
- u8 dest_pci_func;
- int i;
-
- for (i = 0; i < count; i++) {
- src_pci_func = pm_cfg[i].pci_func;
- dest_pci_func = pm_cfg[i].dest_npar;
- if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
- || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
- return QL_STATUS_INVALID_PARAM;
-
- if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
- return QL_STATUS_INVALID_PARAM;
-
- if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
- return QL_STATUS_INVALID_PARAM;
-
- s_esw_id = adapter->npars[src_pci_func].phy_port;
- d_esw_id = adapter->npars[dest_pci_func].phy_port;
-
- if (s_esw_id != d_esw_id)
- return QL_STATUS_INVALID_PARAM;
-
- }
- return 0;
-
-}
-
-static ssize_t
-qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- struct qlcnic_pm_func_cfg *pm_cfg;
- u32 id, action, pci_func;
- int count, rem, i, ret;
-
- count = size / sizeof(struct qlcnic_pm_func_cfg);
- rem = size % sizeof(struct qlcnic_pm_func_cfg);
- if (rem)
- return QL_STATUS_INVALID_PARAM;
-
- pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
-
- ret = validate_pm_config(adapter, pm_cfg, count);
- if (ret)
- return ret;
- for (i = 0; i < count; i++) {
- pci_func = pm_cfg[i].pci_func;
- action = !!pm_cfg[i].action;
- id = adapter->npars[pci_func].phy_port;
- ret = qlcnic_config_port_mirroring(adapter, id,
- action, pci_func);
- if (ret)
- return ret;
- }
-
- for (i = 0; i < count; i++) {
- pci_func = pm_cfg[i].pci_func;
- id = adapter->npars[pci_func].phy_port;
- adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
- adapter->npars[pci_func].dest_npar = id;
- }
- return size;
-}
-
-static ssize_t
-qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
- int i;
-
- if (size != sizeof(pm_cfg))
- return QL_STATUS_INVALID_PARAM;
-
- for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
- if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
- continue;
- pm_cfg[i].action = adapter->npars[i].enable_pm;
- pm_cfg[i].dest_npar = 0;
- pm_cfg[i].pci_func = i;
- }
- memcpy(buf, &pm_cfg, size);
-
- return size;
-}
-
-static int
-validate_esw_config(struct qlcnic_adapter *adapter,
- struct qlcnic_esw_func_cfg *esw_cfg, int count)
-{
- u32 op_mode;
- u8 pci_func;
- int i;
-
- op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
-
- for (i = 0; i < count; i++) {
- pci_func = esw_cfg[i].pci_func;
- if (pci_func >= QLCNIC_MAX_PCI_FUNC)
- return QL_STATUS_INVALID_PARAM;
-
- if (adapter->op_mode == QLCNIC_MGMT_FUNC)
- if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
- return QL_STATUS_INVALID_PARAM;
-
- switch (esw_cfg[i].op_mode) {
- case QLCNIC_PORT_DEFAULTS:
- if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
- QLCNIC_NON_PRIV_FUNC) {
- if (esw_cfg[i].mac_anti_spoof != 0)
- return QL_STATUS_INVALID_PARAM;
- if (esw_cfg[i].mac_override != 1)
- return QL_STATUS_INVALID_PARAM;
- if (esw_cfg[i].promisc_mode != 1)
- return QL_STATUS_INVALID_PARAM;
- }
- break;
- case QLCNIC_ADD_VLAN:
- if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
- return QL_STATUS_INVALID_PARAM;
- if (!esw_cfg[i].op_type)
- return QL_STATUS_INVALID_PARAM;
- break;
- case QLCNIC_DEL_VLAN:
- if (!esw_cfg[i].op_type)
- return QL_STATUS_INVALID_PARAM;
- break;
- default:
- return QL_STATUS_INVALID_PARAM;
- }
- }
- return 0;
-}
-
-static ssize_t
-qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- struct qlcnic_esw_func_cfg *esw_cfg;
- struct qlcnic_npar_info *npar;
- int count, rem, i, ret;
- u8 pci_func, op_mode = 0;
-
- count = size / sizeof(struct qlcnic_esw_func_cfg);
- rem = size % sizeof(struct qlcnic_esw_func_cfg);
- if (rem)
- return QL_STATUS_INVALID_PARAM;
-
- esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
- ret = validate_esw_config(adapter, esw_cfg, count);
- if (ret)
- return ret;
-
- for (i = 0; i < count; i++) {
- if (adapter->op_mode == QLCNIC_MGMT_FUNC)
- if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
- return QL_STATUS_INVALID_PARAM;
-
- if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
- continue;
-
- op_mode = esw_cfg[i].op_mode;
- qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
- esw_cfg[i].op_mode = op_mode;
- esw_cfg[i].pci_func = adapter->ahw->pci_func;
-
- switch (esw_cfg[i].op_mode) {
- case QLCNIC_PORT_DEFAULTS:
- qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
- break;
- case QLCNIC_ADD_VLAN:
- qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
- break;
- case QLCNIC_DEL_VLAN:
- esw_cfg[i].vlan_id = 0;
- qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
- break;
- }
- }
-
- if (adapter->op_mode != QLCNIC_MGMT_FUNC)
- goto out;
-
- for (i = 0; i < count; i++) {
- pci_func = esw_cfg[i].pci_func;
- npar = &adapter->npars[pci_func];
- switch (esw_cfg[i].op_mode) {
- case QLCNIC_PORT_DEFAULTS:
- npar->promisc_mode = esw_cfg[i].promisc_mode;
- npar->mac_override = esw_cfg[i].mac_override;
- npar->offload_flags = esw_cfg[i].offload_flags;
- npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
- npar->discard_tagged = esw_cfg[i].discard_tagged;
- break;
- case QLCNIC_ADD_VLAN:
- npar->pvid = esw_cfg[i].vlan_id;
- break;
- case QLCNIC_DEL_VLAN:
- npar->pvid = 0;
- break;
- }
- }
-out:
- return size;
-}
-
-static ssize_t
-qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
- u8 i;
-
- if (size != sizeof(esw_cfg))
- return QL_STATUS_INVALID_PARAM;
-
- for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
- if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
- continue;
- esw_cfg[i].pci_func = i;
- if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
- return QL_STATUS_INVALID_PARAM;
- }
- memcpy(buf, &esw_cfg, size);
-
- return size;
-}
-
-static int
-validate_npar_config(struct qlcnic_adapter *adapter,
- struct qlcnic_npar_func_cfg *np_cfg, int count)
-{
- u8 pci_func, i;
-
- for (i = 0; i < count; i++) {
- pci_func = np_cfg[i].pci_func;
- if (pci_func >= QLCNIC_MAX_PCI_FUNC)
- return QL_STATUS_INVALID_PARAM;
-
- if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
- return QL_STATUS_INVALID_PARAM;
-
- if (!IS_VALID_BW(np_cfg[i].min_bw) ||
- !IS_VALID_BW(np_cfg[i].max_bw))
- return QL_STATUS_INVALID_PARAM;
- }
- return 0;
-}
-
-static ssize_t
-qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- struct qlcnic_info nic_info;
- struct qlcnic_npar_func_cfg *np_cfg;
- int i, count, rem, ret;
- u8 pci_func;
-
- count = size / sizeof(struct qlcnic_npar_func_cfg);
- rem = size % sizeof(struct qlcnic_npar_func_cfg);
- if (rem)
- return QL_STATUS_INVALID_PARAM;
-
- np_cfg = (struct qlcnic_npar_func_cfg *) buf;
- ret = validate_npar_config(adapter, np_cfg, count);
- if (ret)
- return ret;
-
- for (i = 0; i < count ; i++) {
- pci_func = np_cfg[i].pci_func;
- ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
- if (ret)
- return ret;
- nic_info.pci_func = pci_func;
- nic_info.min_tx_bw = np_cfg[i].min_bw;
- nic_info.max_tx_bw = np_cfg[i].max_bw;
- ret = qlcnic_set_nic_info(adapter, &nic_info);
- if (ret)
- return ret;
- adapter->npars[i].min_bw = nic_info.min_tx_bw;
- adapter->npars[i].max_bw = nic_info.max_tx_bw;
- }
-
- return size;
-
-}
-static ssize_t
-qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- struct qlcnic_info nic_info;
- struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
- int i, ret;
-
- if (size != sizeof(np_cfg))
- return QL_STATUS_INVALID_PARAM;
-
- for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
- if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
- continue;
- ret = qlcnic_get_nic_info(adapter, &nic_info, i);
- if (ret)
- return ret;
-
- np_cfg[i].pci_func = i;
- np_cfg[i].op_mode = (u8)nic_info.op_mode;
- np_cfg[i].port_num = nic_info.phys_port;
- np_cfg[i].fw_capab = nic_info.capabilities;
- np_cfg[i].min_bw = nic_info.min_tx_bw ;
- np_cfg[i].max_bw = nic_info.max_tx_bw;
- np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
- np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
- }
- memcpy(buf, &np_cfg, size);
- return size;
-}
-
-static ssize_t
-qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- struct qlcnic_esw_statistics port_stats;
- int ret;
-
- if (size != sizeof(struct qlcnic_esw_statistics))
- return QL_STATUS_INVALID_PARAM;
-
- if (offset >= QLCNIC_MAX_PCI_FUNC)
- return QL_STATUS_INVALID_PARAM;
-
- memset(&port_stats, 0, size);
- ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
- &port_stats.rx);
- if (ret)
- return ret;
-
- ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
- &port_stats.tx);
- if (ret)
- return ret;
-
- memcpy(buf, &port_stats, size);
- return size;
-}
-
-static ssize_t
-qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- struct qlcnic_esw_statistics esw_stats;
- int ret;
-
- if (size != sizeof(struct qlcnic_esw_statistics))
- return QL_STATUS_INVALID_PARAM;
-
- if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
- return QL_STATUS_INVALID_PARAM;
-
- memset(&esw_stats, 0, size);
- ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
- &esw_stats.rx);
- if (ret)
- return ret;
-
- ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
- &esw_stats.tx);
- if (ret)
- return ret;
-
- memcpy(buf, &esw_stats, size);
- return size;
-}
-
-static ssize_t
-qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- int ret;
-
- if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
- return QL_STATUS_INVALID_PARAM;
-
- ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
- QLCNIC_QUERY_RX_COUNTER);
- if (ret)
- return ret;
-
- ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
- QLCNIC_QUERY_TX_COUNTER);
- if (ret)
- return ret;
-
- return size;
-}
-
-static ssize_t
-qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
-
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- int ret;
-
- if (offset >= QLCNIC_MAX_PCI_FUNC)
- return QL_STATUS_INVALID_PARAM;
-
- ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
- QLCNIC_QUERY_RX_COUNTER);
- if (ret)
- return ret;
-
- ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
- QLCNIC_QUERY_TX_COUNTER);
- if (ret)
- return ret;
-
- return size;
-}
-
-static ssize_t
-qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
- struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
-{
- struct device *dev = container_of(kobj, struct device, kobj);
- struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
- struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
- struct qlcnic_pci_info *pci_info;
- int i, ret;
-
- if (size != sizeof(pci_cfg))
- return QL_STATUS_INVALID_PARAM;
-
- pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
- if (!pci_info)
- return -ENOMEM;
-
- ret = qlcnic_get_pci_info(adapter, pci_info);
- if (ret) {
- kfree(pci_info);
- return ret;
- }
-
- for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
- pci_cfg[i].pci_func = pci_info[i].id;
- pci_cfg[i].func_type = pci_info[i].type;
- pci_cfg[i].port_num = pci_info[i].default_port;
- pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
- pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
- memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
- }
- memcpy(buf, &pci_cfg, size);
- kfree(pci_info);
- return size;
-}
-static struct bin_attribute bin_attr_npar_config = {
- .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
- .size = 0,
- .read = qlcnic_sysfs_read_npar_config,
- .write = qlcnic_sysfs_write_npar_config,
-};
-
-static struct bin_attribute bin_attr_pci_config = {
- .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
- .size = 0,
- .read = qlcnic_sysfs_read_pci_config,
- .write = NULL,
-};
-
-static struct bin_attribute bin_attr_port_stats = {
- .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
- .size = 0,
- .read = qlcnic_sysfs_get_port_stats,
- .write = qlcnic_sysfs_clear_port_stats,
-};
-
-static struct bin_attribute bin_attr_esw_stats = {
- .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
- .size = 0,
- .read = qlcnic_sysfs_get_esw_stats,
- .write = qlcnic_sysfs_clear_esw_stats,
-};
-
-static struct bin_attribute bin_attr_esw_config = {
- .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
- .size = 0,
- .read = qlcnic_sysfs_read_esw_config,
- .write = qlcnic_sysfs_write_esw_config,
-};
-
-static struct bin_attribute bin_attr_pm_config = {
- .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
- .size = 0,
- .read = qlcnic_sysfs_read_pm_config,
- .write = qlcnic_sysfs_write_pm_config,
-};
-
-static void
-qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
-{
- struct device *dev = &adapter->pdev->dev;
-
- if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
- if (device_create_file(dev, &dev_attr_bridged_mode))
- dev_warn(dev,
- "failed to create bridged_mode sysfs entry\n");
-}
-
-static void
-qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
-{
- struct device *dev = &adapter->pdev->dev;
-
- if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
- device_remove_file(dev, &dev_attr_bridged_mode);
-}
-
-static void
-qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
-{
- struct device *dev = &adapter->pdev->dev;
- u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
-
- if (device_create_bin_file(dev, &bin_attr_port_stats))
- dev_info(dev, "failed to create port stats sysfs entry");
-
- if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
- return;
- if (device_create_file(dev, &dev_attr_diag_mode))
- dev_info(dev, "failed to create diag_mode sysfs entry\n");
- if (device_create_bin_file(dev, &bin_attr_crb))
- dev_info(dev, "failed to create crb sysfs entry\n");
- if (device_create_bin_file(dev, &bin_attr_mem))
- dev_info(dev, "failed to create mem sysfs entry\n");
-
- if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
- return;
-
- if (device_create_bin_file(dev, &bin_attr_pci_config))
- dev_info(dev, "failed to create pci config sysfs entry");
- if (device_create_file(dev, &dev_attr_beacon))
- dev_info(dev, "failed to create beacon sysfs entry");
-
- if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
- return;
- if (device_create_bin_file(dev, &bin_attr_esw_config))
- dev_info(dev, "failed to create esw config sysfs entry");
- if (adapter->op_mode != QLCNIC_MGMT_FUNC)
- return;
- if (device_create_bin_file(dev, &bin_attr_npar_config))
- dev_info(dev, "failed to create npar config sysfs entry");
- if (device_create_bin_file(dev, &bin_attr_pm_config))
- dev_info(dev, "failed to create pm config sysfs entry");
- if (device_create_bin_file(dev, &bin_attr_esw_stats))
- dev_info(dev, "failed to create eswitch stats sysfs entry");
-}
-
-static void
-qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
-{
- struct device *dev = &adapter->pdev->dev;
- u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
-
- device_remove_bin_file(dev, &bin_attr_port_stats);
-
- if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
- return;
- device_remove_file(dev, &dev_attr_diag_mode);
- device_remove_bin_file(dev, &bin_attr_crb);
- device_remove_bin_file(dev, &bin_attr_mem);
- if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
- return;
- device_remove_bin_file(dev, &bin_attr_pci_config);
- device_remove_file(dev, &dev_attr_beacon);
- if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
- return;
- device_remove_bin_file(dev, &bin_attr_esw_config);
- if (adapter->op_mode != QLCNIC_MGMT_FUNC)
- return;
- device_remove_bin_file(dev, &bin_attr_npar_config);
- device_remove_bin_file(dev, &bin_attr_pm_config);
- device_remove_bin_file(dev, &bin_attr_esw_stats);
-}
-
#ifdef CONFIG_INET
#define is_qlcnic_netdev(dev) (dev->netdev_ops == &qlcnic_netdev_ops)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
new file mode 100644
index 0000000..e2bad8b
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_sysfs.c
@@ -0,0 +1,951 @@
+#include <linux/slab.h>
+#include <linux/vmalloc.h>
+#include <linux/interrupt.h>
+
+#include "qlcnic.h"
+
+#include <linux/swab.h>
+#include <linux/dma-mapping.h>
+#include <net/ip.h>
+#include <linux/ipv6.h>
+#include <linux/inetdevice.h>
+#include <linux/sysfs.h>
+#include <linux/aer.h>
+#include <linux/log2.h>
+
+#include <linux/sysfs.h>
+
+int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *adapter, u32 enable)
+{
+ return -EOPNOTSUPP;
+}
+
+int qlcnicvf_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
+{
+ return -EOPNOTSUPP;
+}
+
+static ssize_t
+qlcnic_store_bridged_mode(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ unsigned long new;
+ int ret = -EINVAL;
+
+ if (!(adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG))
+ goto err_out;
+
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state))
+ goto err_out;
+
+ if (strict_strtoul(buf, 2, &new))
+ goto err_out;
+
+ if (!adapter->nic_ops->config_bridged_mode(adapter, !!new))
+ ret = len;
+
+err_out:
+ return ret;
+}
+
+static ssize_t
+qlcnic_show_bridged_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ int bridged_mode = 0;
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+ bridged_mode = !!(adapter->flags & QLCNIC_BRIDGE_ENABLED);
+
+ return sprintf(buf, "%d\n", bridged_mode);
+}
+
+static ssize_t
+qlcnic_store_diag_mode(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ unsigned long new;
+
+ if (strict_strtoul(buf, 2, &new))
+ return -EINVAL;
+
+ if (!!new != !!(adapter->flags & QLCNIC_DIAG_ENABLED))
+ adapter->flags ^= QLCNIC_DIAG_ENABLED;
+
+ return len;
+}
+
+static ssize_t
+qlcnic_show_diag_mode(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n",
+ !!(adapter->flags & QLCNIC_DIAG_ENABLED));
+}
+
+static int
+qlcnic_validate_beacon(struct qlcnic_adapter *adapter, u16 beacon, u8 *state,
+ u8 *rate)
+{
+ *rate = LSB(beacon);
+ *state = MSB(beacon);
+
+ QLCDB(adapter, DRV, "rate %x state %x\n", *rate, *state);
+
+ if (!*state) {
+ *rate = __QLCNIC_MAX_LED_RATE;
+ return 0;
+ } else if (*state > __QLCNIC_MAX_LED_STATE)
+ return -EINVAL;
+
+ if ((!*rate) || (*rate > __QLCNIC_MAX_LED_RATE))
+ return -EINVAL;
+
+ return 0;
+}
+
+static ssize_t
+qlcnic_store_beacon(struct device *dev,
+ struct device_attribute *attr, const char *buf, size_t len)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ int max_sds_rings = adapter->max_sds_rings;
+ u16 beacon;
+ u8 b_state, b_rate;
+ int err;
+
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC) {
+ dev_warn(dev, "LED test not supported for non "
+ "privilege function\n");
+ return -EOPNOTSUPP;
+ }
+
+ if (len != sizeof(u16))
+ return QL_STATUS_INVALID_PARAM;
+
+ memcpy(&beacon, buf, sizeof(u16));
+ err = qlcnic_validate_beacon(adapter, beacon, &b_state, &b_rate);
+ if (err)
+ return err;
+
+ if (adapter->ahw->beacon_state == b_state)
+ return len;
+
+ rtnl_lock();
+
+ if (!adapter->ahw->beacon_state)
+ if (test_and_set_bit(__QLCNIC_LED_ENABLE, &adapter->state)) {
+ rtnl_unlock();
+ return -EBUSY;
+ }
+
+ if (test_bit(__QLCNIC_RESETTING, &adapter->state)) {
+ err = -EIO;
+ goto out;
+ }
+
+ if (!test_bit(__QLCNIC_DEV_UP, &adapter->state)) {
+ err = qlcnic_diag_alloc_res(adapter->netdev, QLCNIC_LED_TEST);
+ if (err)
+ goto out;
+ set_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state);
+ }
+
+ err = qlcnic_config_led(adapter, b_state, b_rate);
+
+ if (!err) {
+ err = len;
+ adapter->ahw->beacon_state = b_state;
+ }
+
+ if (test_and_clear_bit(__QLCNIC_DIAG_RES_ALLOC, &adapter->state))
+ qlcnic_diag_free_res(adapter->netdev, max_sds_rings);
+
+ out:
+ if (!adapter->ahw->beacon_state)
+ clear_bit(__QLCNIC_LED_ENABLE, &adapter->state);
+ rtnl_unlock();
+
+ return err;
+}
+
+static ssize_t
+qlcnic_show_beacon(struct device *dev,
+ struct device_attribute *attr, char *buf)
+{
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+
+ return sprintf(buf, "%d\n", adapter->ahw->beacon_state);
+}
+
+static int
+qlcnic_sysfs_validate_crb(struct qlcnic_adapter *adapter,
+ loff_t offset, size_t size)
+{
+ size_t crb_size = 4;
+
+ if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
+ return -EIO;
+
+ if (offset < QLCNIC_PCI_CRBSPACE) {
+ if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM,
+ QLCNIC_PCI_CAMQM_END))
+ crb_size = 8;
+ else
+ return -EINVAL;
+ }
+
+ if ((size != crb_size) || (offset & (crb_size-1)))
+ return -EINVAL;
+
+ return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_read_crb(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u32 data;
+ u64 qmdata;
+ int ret;
+
+ ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+ qlcnic_pci_camqm_read_2M(adapter, offset, &qmdata);
+ memcpy(buf, &qmdata, size);
+ } else {
+ data = QLCRD32(adapter, offset);
+ memcpy(buf, &data, size);
+ }
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_write_crb(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u32 data;
+ u64 qmdata;
+ int ret;
+
+ ret = qlcnic_sysfs_validate_crb(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ if (ADDR_IN_RANGE(offset, QLCNIC_PCI_CAMQM, QLCNIC_PCI_CAMQM_END)) {
+ memcpy(&qmdata, buf, size);
+ qlcnic_pci_camqm_write_2M(adapter, offset, qmdata);
+ } else {
+ memcpy(&data, buf, size);
+ QLCWR32(adapter, offset, data);
+ }
+ return size;
+}
+
+static int
+qlcnic_sysfs_validate_mem(struct qlcnic_adapter *adapter,
+ loff_t offset, size_t size)
+{
+ if (!(adapter->flags & QLCNIC_DIAG_ENABLED))
+ return -EIO;
+
+ if ((size != 8) || (offset & 0x7))
+ return -EIO;
+
+ return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_read_mem(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u64 data;
+ int ret;
+
+ ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ if (qlcnic_pci_mem_read_2M(adapter, offset, &data))
+ return -EIO;
+
+ memcpy(buf, &data, size);
+
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_write_mem(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr,
+ char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ u64 data;
+ int ret;
+
+ ret = qlcnic_sysfs_validate_mem(adapter, offset, size);
+ if (ret != 0)
+ return ret;
+
+ memcpy(&data, buf, size);
+
+ if (qlcnic_pci_mem_write_2M(adapter, offset, data))
+ return -EIO;
+
+ return size;
+}
+
+static int
+validate_pm_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_pm_func_cfg *pm_cfg, int count)
+{
+
+ u8 src_pci_func, s_esw_id, d_esw_id;
+ u8 dest_pci_func;
+ int i;
+
+ for (i = 0; i < count; i++) {
+ src_pci_func = pm_cfg[i].pci_func;
+ dest_pci_func = pm_cfg[i].dest_npar;
+ if (src_pci_func >= QLCNIC_MAX_PCI_FUNC
+ || dest_pci_func >= QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (adapter->npars[src_pci_func].type != QLCNIC_TYPE_NIC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (adapter->npars[dest_pci_func].type != QLCNIC_TYPE_NIC)
+ return QL_STATUS_INVALID_PARAM;
+
+ s_esw_id = adapter->npars[src_pci_func].phy_port;
+ d_esw_id = adapter->npars[dest_pci_func].phy_port;
+
+ if (s_esw_id != d_esw_id)
+ return QL_STATUS_INVALID_PARAM;
+
+ }
+ return 0;
+
+}
+
+static ssize_t
+qlcnic_sysfs_write_pm_config(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_pm_func_cfg *pm_cfg;
+ u32 id, action, pci_func;
+ int count, rem, i, ret;
+
+ count = size / sizeof(struct qlcnic_pm_func_cfg);
+ rem = size % sizeof(struct qlcnic_pm_func_cfg);
+ if (rem)
+ return QL_STATUS_INVALID_PARAM;
+
+ pm_cfg = (struct qlcnic_pm_func_cfg *) buf;
+
+ ret = validate_pm_config(adapter, pm_cfg, count);
+ if (ret)
+ return ret;
+ for (i = 0; i < count; i++) {
+ pci_func = pm_cfg[i].pci_func;
+ action = !!pm_cfg[i].action;
+ id = adapter->npars[pci_func].phy_port;
+ ret = qlcnic_config_port_mirroring(adapter, id,
+ action, pci_func);
+ if (ret)
+ return ret;
+ }
+
+ for (i = 0; i < count; i++) {
+ pci_func = pm_cfg[i].pci_func;
+ id = adapter->npars[pci_func].phy_port;
+ adapter->npars[pci_func].enable_pm = !!pm_cfg[i].action;
+ adapter->npars[pci_func].dest_npar = id;
+ }
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pm_config(struct file *filp, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_pm_func_cfg pm_cfg[QLCNIC_MAX_PCI_FUNC];
+ int i;
+
+ if (size != sizeof(pm_cfg))
+ return QL_STATUS_INVALID_PARAM;
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+ continue;
+ pm_cfg[i].action = adapter->npars[i].enable_pm;
+ pm_cfg[i].dest_npar = 0;
+ pm_cfg[i].pci_func = i;
+ }
+ memcpy(buf, &pm_cfg, size);
+
+ return size;
+}
+
+static int
+validate_esw_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_esw_func_cfg *esw_cfg, int count)
+{
+ u32 op_mode;
+ u8 pci_func;
+ int i;
+
+ op_mode = readl(adapter->ahw->pci_base0 + QLCNIC_DRV_OP_MODE);
+
+ for (i = 0; i < count; i++) {
+ pci_func = esw_cfg[i].pci_func;
+ if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+ if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+ return QL_STATUS_INVALID_PARAM;
+
+ switch (esw_cfg[i].op_mode) {
+ case QLCNIC_PORT_DEFAULTS:
+ if (QLC_DEV_GET_DRV(op_mode, pci_func) !=
+ QLCNIC_NON_PRIV_FUNC) {
+ if (esw_cfg[i].mac_anti_spoof != 0)
+ return QL_STATUS_INVALID_PARAM;
+ if (esw_cfg[i].mac_override != 1)
+ return QL_STATUS_INVALID_PARAM;
+ if (esw_cfg[i].promisc_mode != 1)
+ return QL_STATUS_INVALID_PARAM;
+ }
+ break;
+ case QLCNIC_ADD_VLAN:
+ if (!IS_VALID_VLAN(esw_cfg[i].vlan_id))
+ return QL_STATUS_INVALID_PARAM;
+ if (!esw_cfg[i].op_type)
+ return QL_STATUS_INVALID_PARAM;
+ break;
+ case QLCNIC_DEL_VLAN:
+ if (!esw_cfg[i].op_type)
+ return QL_STATUS_INVALID_PARAM;
+ break;
+ default:
+ return QL_STATUS_INVALID_PARAM;
+ }
+ }
+ return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_esw_config(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_esw_func_cfg *esw_cfg;
+ struct qlcnic_npar_info *npar;
+ int count, rem, i, ret;
+ u8 pci_func, op_mode = 0;
+
+ count = size / sizeof(struct qlcnic_esw_func_cfg);
+ rem = size % sizeof(struct qlcnic_esw_func_cfg);
+ if (rem)
+ return QL_STATUS_INVALID_PARAM;
+
+ esw_cfg = (struct qlcnic_esw_func_cfg *) buf;
+ ret = validate_esw_config(adapter, esw_cfg, count);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < count; i++) {
+ if (adapter->op_mode == QLCNIC_MGMT_FUNC)
+ if (qlcnic_config_switch_port(adapter, &esw_cfg[i]))
+ return QL_STATUS_INVALID_PARAM;
+
+ if (adapter->ahw->pci_func != esw_cfg[i].pci_func)
+ continue;
+
+ op_mode = esw_cfg[i].op_mode;
+ qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]);
+ esw_cfg[i].op_mode = op_mode;
+ esw_cfg[i].pci_func = adapter->ahw->pci_func;
+
+ switch (esw_cfg[i].op_mode) {
+ case QLCNIC_PORT_DEFAULTS:
+ qlcnic_set_eswitch_port_features(adapter, &esw_cfg[i]);
+ break;
+ case QLCNIC_ADD_VLAN:
+ qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
+ break;
+ case QLCNIC_DEL_VLAN:
+ esw_cfg[i].vlan_id = 0;
+ qlcnic_set_vlan_config(adapter, &esw_cfg[i]);
+ break;
+ }
+ }
+
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ goto out;
+
+ for (i = 0; i < count; i++) {
+ pci_func = esw_cfg[i].pci_func;
+ npar = &adapter->npars[pci_func];
+ switch (esw_cfg[i].op_mode) {
+ case QLCNIC_PORT_DEFAULTS:
+ npar->promisc_mode = esw_cfg[i].promisc_mode;
+ npar->mac_override = esw_cfg[i].mac_override;
+ npar->offload_flags = esw_cfg[i].offload_flags;
+ npar->mac_anti_spoof = esw_cfg[i].mac_anti_spoof;
+ npar->discard_tagged = esw_cfg[i].discard_tagged;
+ break;
+ case QLCNIC_ADD_VLAN:
+ npar->pvid = esw_cfg[i].vlan_id;
+ break;
+ case QLCNIC_DEL_VLAN:
+ npar->pvid = 0;
+ break;
+ }
+ }
+out:
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_esw_config(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_esw_func_cfg esw_cfg[QLCNIC_MAX_PCI_FUNC];
+ u8 i;
+
+ if (size != sizeof(esw_cfg))
+ return QL_STATUS_INVALID_PARAM;
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC; i++) {
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+ continue;
+ esw_cfg[i].pci_func = i;
+ if (qlcnic_get_eswitch_port_config(adapter, &esw_cfg[i]))
+ return QL_STATUS_INVALID_PARAM;
+ }
+ memcpy(buf, &esw_cfg, size);
+
+ return size;
+}
+
+static int
+validate_npar_config(struct qlcnic_adapter *adapter,
+ struct qlcnic_npar_func_cfg *np_cfg, int count)
+{
+ u8 pci_func, i;
+
+ for (i = 0; i < count; i++) {
+ pci_func = np_cfg[i].pci_func;
+ if (pci_func >= QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (adapter->npars[pci_func].type != QLCNIC_TYPE_NIC)
+ return QL_STATUS_INVALID_PARAM;
+
+ if (!IS_VALID_BW(np_cfg[i].min_bw) ||
+ !IS_VALID_BW(np_cfg[i].max_bw))
+ return QL_STATUS_INVALID_PARAM;
+ }
+ return 0;
+}
+
+static ssize_t
+qlcnic_sysfs_write_npar_config(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_info nic_info;
+ struct qlcnic_npar_func_cfg *np_cfg;
+ int i, count, rem, ret;
+ u8 pci_func;
+
+ count = size / sizeof(struct qlcnic_npar_func_cfg);
+ rem = size % sizeof(struct qlcnic_npar_func_cfg);
+ if (rem)
+ return QL_STATUS_INVALID_PARAM;
+
+ np_cfg = (struct qlcnic_npar_func_cfg *) buf;
+ ret = validate_npar_config(adapter, np_cfg, count);
+ if (ret)
+ return ret;
+
+ for (i = 0; i < count ; i++) {
+ pci_func = np_cfg[i].pci_func;
+ ret = qlcnic_get_nic_info(adapter, &nic_info, pci_func);
+ if (ret)
+ return ret;
+ nic_info.pci_func = pci_func;
+ nic_info.min_tx_bw = np_cfg[i].min_bw;
+ nic_info.max_tx_bw = np_cfg[i].max_bw;
+ ret = qlcnic_set_nic_info(adapter, &nic_info);
+ if (ret)
+ return ret;
+ adapter->npars[i].min_bw = nic_info.min_tx_bw;
+ adapter->npars[i].max_bw = nic_info.max_tx_bw;
+ }
+
+ return size;
+
+}
+static ssize_t
+qlcnic_sysfs_read_npar_config(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_info nic_info;
+ struct qlcnic_npar_func_cfg np_cfg[QLCNIC_MAX_PCI_FUNC];
+ int i, ret;
+
+ if (size != sizeof(np_cfg))
+ return QL_STATUS_INVALID_PARAM;
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+ if (adapter->npars[i].type != QLCNIC_TYPE_NIC)
+ continue;
+ ret = qlcnic_get_nic_info(adapter, &nic_info, i);
+ if (ret)
+ return ret;
+
+ np_cfg[i].pci_func = i;
+ np_cfg[i].op_mode = (u8)nic_info.op_mode;
+ np_cfg[i].port_num = nic_info.phys_port;
+ np_cfg[i].fw_capab = nic_info.capabilities;
+ np_cfg[i].min_bw = nic_info.min_tx_bw ;
+ np_cfg[i].max_bw = nic_info.max_tx_bw;
+ np_cfg[i].max_tx_queues = nic_info.max_tx_ques;
+ np_cfg[i].max_rx_queues = nic_info.max_rx_ques;
+ }
+ memcpy(buf, &np_cfg, size);
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_get_port_stats(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_esw_statistics port_stats;
+ int ret;
+
+ if (size != sizeof(struct qlcnic_esw_statistics))
+ return QL_STATUS_INVALID_PARAM;
+
+ if (offset >= QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+
+ memset(&port_stats, 0, size);
+ ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
+ &port_stats.rx);
+ if (ret)
+ return ret;
+
+ ret = qlcnic_get_port_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
+ &port_stats.tx);
+ if (ret)
+ return ret;
+
+ memcpy(buf, &port_stats, size);
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_get_esw_stats(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_esw_statistics esw_stats;
+ int ret;
+
+ if (size != sizeof(struct qlcnic_esw_statistics))
+ return QL_STATUS_INVALID_PARAM;
+
+ if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
+ return QL_STATUS_INVALID_PARAM;
+
+ memset(&esw_stats, 0, size);
+ ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_RX_COUNTER,
+ &esw_stats.rx);
+ if (ret)
+ return ret;
+
+ ret = qlcnic_get_eswitch_stats(adapter, offset, QLCNIC_QUERY_TX_COUNTER,
+ &esw_stats.tx);
+ if (ret)
+ return ret;
+
+ memcpy(buf, &esw_stats, size);
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_clear_esw_stats(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ int ret;
+
+ if (offset >= QLCNIC_NIU_MAX_XG_PORTS)
+ return QL_STATUS_INVALID_PARAM;
+
+ ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
+ QLCNIC_QUERY_RX_COUNTER);
+ if (ret)
+ return ret;
+
+ ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_ESWITCH, offset,
+ QLCNIC_QUERY_TX_COUNTER);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_clear_port_stats(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ int ret;
+
+ if (offset >= QLCNIC_MAX_PCI_FUNC)
+ return QL_STATUS_INVALID_PARAM;
+
+ ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
+ QLCNIC_QUERY_RX_COUNTER);
+ if (ret)
+ return ret;
+
+ ret = qlcnic_clear_esw_stats(adapter, QLCNIC_STATS_PORT, offset,
+ QLCNIC_QUERY_TX_COUNTER);
+ if (ret)
+ return ret;
+
+ return size;
+}
+
+static ssize_t
+qlcnic_sysfs_read_pci_config(struct file *file, struct kobject *kobj,
+ struct bin_attribute *attr, char *buf, loff_t offset, size_t size)
+{
+ struct device *dev = container_of(kobj, struct device, kobj);
+ struct qlcnic_adapter *adapter = dev_get_drvdata(dev);
+ struct qlcnic_pci_func_cfg pci_cfg[QLCNIC_MAX_PCI_FUNC];
+ struct qlcnic_pci_info *pci_info;
+ int i, ret;
+
+ if (size != sizeof(pci_cfg))
+ return QL_STATUS_INVALID_PARAM;
+
+ pci_info = kcalloc(QLCNIC_MAX_PCI_FUNC, sizeof(*pci_info), GFP_KERNEL);
+ if (!pci_info)
+ return -ENOMEM;
+
+ ret = qlcnic_get_pci_info(adapter, pci_info);
+ if (ret) {
+ kfree(pci_info);
+ return ret;
+ }
+
+ for (i = 0; i < QLCNIC_MAX_PCI_FUNC ; i++) {
+ pci_cfg[i].pci_func = pci_info[i].id;
+ pci_cfg[i].func_type = pci_info[i].type;
+ pci_cfg[i].port_num = pci_info[i].default_port;
+ pci_cfg[i].min_bw = pci_info[i].tx_min_bw;
+ pci_cfg[i].max_bw = pci_info[i].tx_max_bw;
+ memcpy(&pci_cfg[i].def_mac_addr, &pci_info[i].mac, ETH_ALEN);
+ }
+ memcpy(buf, &pci_cfg, size);
+ kfree(pci_info);
+ return size;
+}
+
+static struct device_attribute dev_attr_bridged_mode = {
+ .attr = {.name = "bridged_mode", .mode = (S_IRUGO | S_IWUSR)},
+ .show = qlcnic_show_bridged_mode,
+ .store = qlcnic_store_bridged_mode,
+};
+
+static struct device_attribute dev_attr_diag_mode = {
+ .attr = {.name = "diag_mode", .mode = (S_IRUGO | S_IWUSR)},
+ .show = qlcnic_show_diag_mode,
+ .store = qlcnic_store_diag_mode,
+};
+
+static struct device_attribute dev_attr_beacon = {
+ .attr = {.name = "beacon", .mode = (S_IRUGO | S_IWUSR)},
+ .show = qlcnic_show_beacon,
+ .store = qlcnic_store_beacon,
+};
+
+static struct bin_attribute bin_attr_crb = {
+ .attr = {.name = "crb", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_crb,
+ .write = qlcnic_sysfs_write_crb,
+};
+
+static struct bin_attribute bin_attr_mem = {
+ .attr = {.name = "mem", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_mem,
+ .write = qlcnic_sysfs_write_mem,
+};
+
+static struct bin_attribute bin_attr_npar_config = {
+ .attr = {.name = "npar_config", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_npar_config,
+ .write = qlcnic_sysfs_write_npar_config,
+};
+
+static struct bin_attribute bin_attr_pci_config = {
+ .attr = {.name = "pci_config", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_pci_config,
+ .write = NULL,
+};
+
+static struct bin_attribute bin_attr_port_stats = {
+ .attr = {.name = "port_stats", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_get_port_stats,
+ .write = qlcnic_sysfs_clear_port_stats,
+};
+
+static struct bin_attribute bin_attr_esw_stats = {
+ .attr = {.name = "esw_stats", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_get_esw_stats,
+ .write = qlcnic_sysfs_clear_esw_stats,
+};
+
+static struct bin_attribute bin_attr_esw_config = {
+ .attr = {.name = "esw_config", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_esw_config,
+ .write = qlcnic_sysfs_write_esw_config,
+};
+
+static struct bin_attribute bin_attr_pm_config = {
+ .attr = {.name = "pm_config", .mode = (S_IRUGO | S_IWUSR)},
+ .size = 0,
+ .read = qlcnic_sysfs_read_pm_config,
+ .write = qlcnic_sysfs_write_pm_config,
+};
+
+void qlcnic_create_sysfs_entries(struct qlcnic_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+ if (device_create_file(dev, &dev_attr_bridged_mode))
+ dev_warn(dev,
+ "failed to create bridged_mode sysfs entry\n");
+}
+
+void qlcnic_remove_sysfs_entries(struct qlcnic_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+
+ if (adapter->capabilities & QLCNIC_FW_CAPABILITY_BDG)
+ device_remove_file(dev, &dev_attr_bridged_mode);
+}
+
+void qlcnic_create_diag_entries(struct qlcnic_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+ u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+
+ if (device_create_bin_file(dev, &bin_attr_port_stats))
+ dev_info(dev, "failed to create port stats sysfs entry");
+
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+ return;
+ if (device_create_file(dev, &dev_attr_diag_mode))
+ dev_info(dev, "failed to create diag_mode sysfs entry\n");
+ if (device_create_bin_file(dev, &bin_attr_crb))
+ dev_info(dev, "failed to create crb sysfs entry\n");
+ if (device_create_bin_file(dev, &bin_attr_mem))
+ dev_info(dev, "failed to create mem sysfs entry\n");
+
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
+ return;
+
+ if (device_create_bin_file(dev, &bin_attr_pci_config))
+ dev_info(dev, "failed to create pci config sysfs entry");
+ if (device_create_file(dev, &dev_attr_beacon))
+ dev_info(dev, "failed to create beacon sysfs entry");
+
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+ return;
+ if (device_create_bin_file(dev, &bin_attr_esw_config))
+ dev_info(dev, "failed to create esw config sysfs entry");
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return;
+ if (device_create_bin_file(dev, &bin_attr_npar_config))
+ dev_info(dev, "failed to create npar config sysfs entry");
+ if (device_create_bin_file(dev, &bin_attr_pm_config))
+ dev_info(dev, "failed to create pm config sysfs entry");
+ if (device_create_bin_file(dev, &bin_attr_esw_stats))
+ dev_info(dev, "failed to create eswitch stats sysfs entry");
+}
+
+void qlcnic_remove_diag_entries(struct qlcnic_adapter *adapter)
+{
+ struct device *dev = &adapter->pdev->dev;
+ u32 state = QLCRD32(adapter, QLCNIC_CRB_DEV_STATE);
+
+ device_remove_bin_file(dev, &bin_attr_port_stats);
+
+ if (adapter->op_mode == QLCNIC_NON_PRIV_FUNC)
+ return;
+ device_remove_file(dev, &dev_attr_diag_mode);
+ device_remove_bin_file(dev, &bin_attr_crb);
+ device_remove_bin_file(dev, &bin_attr_mem);
+ if (state == QLCNIC_DEV_FAILED || (state == QLCNIC_DEV_BADBAD))
+ return;
+ device_remove_bin_file(dev, &bin_attr_pci_config);
+ device_remove_file(dev, &dev_attr_beacon);
+ if (!(adapter->flags & QLCNIC_ESWITCH_ENABLED))
+ return;
+ device_remove_bin_file(dev, &bin_attr_esw_config);
+ if (adapter->op_mode != QLCNIC_MGMT_FUNC)
+ return;
+ device_remove_bin_file(dev, &bin_attr_npar_config);
+ device_remove_bin_file(dev, &bin_attr_pm_config);
+ device_remove_bin_file(dev, &bin_attr_esw_stats);
+}
--
1.7.1
^ permalink raw reply related
* [PATCH 6/6] qlcnic: fix coding style issues in qlcnic_minidump.c
From: Sony Chacko @ 2012-11-28 14:34 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
In-Reply-To: <1354113271-23850-1-git-send-email-sony.chacko@qlogic.com>
From: Sony Chacko <sony.chacko@qlogic.com>
Fix coding style violations in qlcnic_minidump.c
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
---
.../net/ethernet/qlogic/qlcnic/qlcnic_minidump.c | 34 ++++++++++----------
1 files changed, 17 insertions(+), 17 deletions(-)
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
index 5e22c62..12ff292 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -115,7 +115,7 @@ struct qlcnic_dump_entry {
} region;
} __packed;
-enum op_codes {
+enum qlcnic_minidump_opcode {
QLCNIC_DUMP_NOP = 0,
QLCNIC_DUMP_READ_CRB = 1,
QLCNIC_DUMP_READ_MUX = 2,
@@ -139,7 +139,7 @@ enum op_codes {
};
struct qlcnic_dump_operations {
- enum op_codes opcode;
+ enum qlcnic_minidump_opcode opcode;
u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *,
__le32 *);
};
@@ -269,7 +269,7 @@ static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
break;
default:
dev_info(&adapter->pdev->dev,
- "Unknown opcode\n");
+ "Unknown opcode\n");
break;
}
}
@@ -455,8 +455,8 @@ static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
/* check for data size of multiple of 16 and 16 byte alignment */
if ((addr & 0xf) || (reg_read%16)) {
dev_info(&adapter->pdev->dev,
- "Unaligned memory addr:0x%x size:0x%x\n",
- addr, reg_read);
+ "Unaligned memory addr:0x%x size:0x%x\n",
+ addr, reg_read);
return -EINVAL;
}
@@ -528,12 +528,12 @@ static const struct qlcnic_dump_operations fw_dump_ops[] = {
/* Walk the template and collect dump for each entry in the dump template */
static int
qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry,
- u32 size)
+ u32 size)
{
int ret = 1;
if (size != entry->hdr.cap_size) {
dev_info(dev,
- "Invalidate dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
+ "Invalid dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size);
dev_info(dev, "Aborting further dump capture\n");
ret = 0;
@@ -554,7 +554,7 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
if (fw_dump->clr) {
dev_info(&adapter->pdev->dev,
- "Previous dump not cleared, not capturing dump\n");
+ "Previous dump not cleared, not capturing dump\n");
return -EIO;
}
/* Calculate the size for dump data area only */
@@ -567,8 +567,8 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
fw_dump->data = vzalloc(dump_size);
if (!fw_dump->data) {
dev_info(&adapter->pdev->dev,
- "Unable to allocate (%d KB) for fw dump\n",
- dump_size/1024);
+ "Unable to allocate (%d KB) for fw dump\n",
+ dump_size / 1024);
return -ENOMEM;
}
buffer = fw_dump->data;
@@ -595,14 +595,14 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
}
if (ops_index == ops_cnt) {
dev_info(&adapter->pdev->dev,
- "Invalid entry type %d, exiting dump\n",
- entry->hdr.type);
+ "Invalid entry type %d, exiting dump\n",
+ entry->hdr.type);
goto error;
}
/* Collect dump for this entry */
dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
if (dump && !qlcnic_valid_dump_entry(&adapter->pdev->dev, entry,
- dump))
+ dump))
entry->hdr.flags |= QLCNIC_DUMP_SKIP;
buf_offset += entry->hdr.cap_size;
entry_offset += entry->hdr.offset;
@@ -610,15 +610,15 @@ int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
}
if (dump_size != buf_offset) {
dev_info(&adapter->pdev->dev,
- "Captured(%d) and expected size(%d) do not match\n",
- buf_offset, dump_size);
+ "Captured(%d) and expected size(%d) do not match\n",
+ buf_offset, dump_size);
goto error;
} else {
fw_dump->clr = 1;
snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
- adapter->netdev->name);
+ adapter->netdev->name);
dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n",
- fw_dump->size);
+ fw_dump->size);
/* Send a udev event to notify availability of FW dump */
kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg);
return 0;
--
1.7.1
^ permalink raw reply related
* [PATCH 5/6] qlcnic: create file qlcnic_minidump.c for dump utility
From: Sony Chacko @ 2012-11-28 14:34 UTC (permalink / raw)
To: davem; +Cc: netdev, Dept_NX_Linux_NIC_Driver, Sony Chacko
In-Reply-To: <1354113271-23850-1-git-send-email-sony.chacko@qlogic.com>
From: Sony Chacko <sony.chacko@qlogic.com>
Physical refactoring of 82xx adapter register dump utility.
Move register dump routines to new file qlcnic_minidump.c
Existing register dump routines has coding style issues, the code
is moved to the new file without fixing the style issues.
There is a seperate patch to fix the style issues in qlcnic_minidump.c
Signed-off-by: Sony Chacko <sony.chacko@qlogic.com>
---
drivers/net/ethernet/qlogic/qlcnic/Makefile | 2 +-
drivers/net/ethernet/qlogic/qlcnic/qlcnic.h | 143 +-----
drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c | 486 ---------------
.../net/ethernet/qlogic/qlcnic/qlcnic_minidump.c | 629 ++++++++++++++++++++
4 files changed, 632 insertions(+), 628 deletions(-)
create mode 100644 drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
diff --git a/drivers/net/ethernet/qlogic/qlcnic/Makefile b/drivers/net/ethernet/qlogic/qlcnic/Makefile
index 34db053..c4b8ced 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/Makefile
+++ b/drivers/net/ethernet/qlogic/qlcnic/Makefile
@@ -6,4 +6,4 @@ obj-$(CONFIG_QLCNIC) := qlcnic.o
qlcnic-y := qlcnic_hw.o qlcnic_main.o qlcnic_init.o \
qlcnic_ethtool.o qlcnic_ctx.o qlcnic_io.o \
- qlcnic_sysfs.o
+ qlcnic_sysfs.o qlcnic_minidump.o
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
index 618e5ec..082eecb 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic.h
@@ -1255,142 +1255,7 @@ struct qlcnic_esw_statistics {
struct __qlcnic_esw_statistics tx;
};
-struct qlcnic_common_entry_hdr {
- u32 type;
- u32 offset;
- u32 cap_size;
- u8 mask;
- u8 rsvd[2];
- u8 flags;
-} __packed;
-
-struct __crb {
- u32 addr;
- u8 stride;
- u8 rsvd1[3];
- u32 data_size;
- u32 no_ops;
- u32 rsvd2[4];
-} __packed;
-
-struct __ctrl {
- u32 addr;
- u8 stride;
- u8 index_a;
- u16 timeout;
- u32 data_size;
- u32 no_ops;
- u8 opcode;
- u8 index_v;
- u8 shl_val;
- u8 shr_val;
- u32 val1;
- u32 val2;
- u32 val3;
-} __packed;
-
-struct __cache {
- u32 addr;
- u16 stride;
- u16 init_tag_val;
- u32 size;
- u32 no_ops;
- u32 ctrl_addr;
- u32 ctrl_val;
- u32 read_addr;
- u8 read_addr_stride;
- u8 read_addr_num;
- u8 rsvd1[2];
-} __packed;
-
-struct __ocm {
- u8 rsvd[8];
- u32 size;
- u32 no_ops;
- u8 rsvd1[8];
- u32 read_addr;
- u32 read_addr_stride;
-} __packed;
-
-struct __mem {
- u8 rsvd[24];
- u32 addr;
- u32 size;
-} __packed;
-
-struct __mux {
- u32 addr;
- u8 rsvd[4];
- u32 size;
- u32 no_ops;
- u32 val;
- u32 val_stride;
- u32 read_addr;
- u8 rsvd2[4];
-} __packed;
-
-struct __queue {
- u32 sel_addr;
- u16 stride;
- u8 rsvd[2];
- u32 size;
- u32 no_ops;
- u8 rsvd2[8];
- u32 read_addr;
- u8 read_addr_stride;
- u8 read_addr_cnt;
- u8 rsvd3[2];
-} __packed;
-
-struct qlcnic_dump_entry {
- struct qlcnic_common_entry_hdr hdr;
- union {
- struct __crb crb;
- struct __cache cache;
- struct __ocm ocm;
- struct __mem mem;
- struct __mux mux;
- struct __queue que;
- struct __ctrl ctrl;
- } region;
-} __packed;
-
-enum op_codes {
- QLCNIC_DUMP_NOP = 0,
- QLCNIC_DUMP_READ_CRB = 1,
- QLCNIC_DUMP_READ_MUX = 2,
- QLCNIC_DUMP_QUEUE = 3,
- QLCNIC_DUMP_BRD_CONFIG = 4,
- QLCNIC_DUMP_READ_OCM = 6,
- QLCNIC_DUMP_PEG_REG = 7,
- QLCNIC_DUMP_L1_DTAG = 8,
- QLCNIC_DUMP_L1_ITAG = 9,
- QLCNIC_DUMP_L1_DATA = 11,
- QLCNIC_DUMP_L1_INST = 12,
- QLCNIC_DUMP_L2_DTAG = 21,
- QLCNIC_DUMP_L2_ITAG = 22,
- QLCNIC_DUMP_L2_DATA = 23,
- QLCNIC_DUMP_L2_INST = 24,
- QLCNIC_DUMP_READ_ROM = 71,
- QLCNIC_DUMP_READ_MEM = 72,
- QLCNIC_DUMP_READ_CTRL = 98,
- QLCNIC_DUMP_TLHDR = 99,
- QLCNIC_DUMP_RDEND = 255
-};
-
-#define QLCNIC_DUMP_WCRB BIT_0
-#define QLCNIC_DUMP_RWCRB BIT_1
-#define QLCNIC_DUMP_ANDCRB BIT_2
-#define QLCNIC_DUMP_ORCRB BIT_3
-#define QLCNIC_DUMP_POLLCRB BIT_4
-#define QLCNIC_DUMP_RD_SAVE BIT_5
-#define QLCNIC_DUMP_WRT_SAVED BIT_6
-#define QLCNIC_DUMP_MOD_SAVE_ST BIT_7
-#define QLCNIC_DUMP_SKIP BIT_7
-
-#define QLCNIC_DUMP_MASK_MIN 3
#define QLCNIC_DUMP_MASK_DEF 0x1f
-#define QLCNIC_DUMP_MASK_MAX 0xff
#define QLCNIC_FORCE_FW_DUMP_KEY 0xdeadfeed
#define QLCNIC_ENABLE_FW_DUMP 0xaddfeed
#define QLCNIC_DISABLE_FW_DUMP 0xbadfeed
@@ -1398,12 +1263,6 @@ enum op_codes {
#define QLCNIC_SET_QUIESCENT 0xadd00010
#define QLCNIC_RESET_QUIESCENT 0xadd00020
-struct qlcnic_dump_operations {
- enum op_codes opcode;
- u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *,
- __le32 *);
-};
-
struct _cdrp_cmd {
u32 cmd;
u32 arg1;
@@ -1461,6 +1320,8 @@ void qlcnic_pcie_sem_unlock(struct qlcnic_adapter *, int);
#define __QLCNIC_MAX_LED_RATE 0xf
#define __QLCNIC_MAX_LED_STATE 0x2
+#define MAX_CTL_CHECK 1000
+
int qlcnic_get_board_info(struct qlcnic_adapter *adapter);
int qlcnic_wol_supported(struct qlcnic_adapter *adapter);
int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate);
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
index aeacf1d..ff879cd 100644
--- a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_hw.c
@@ -266,33 +266,6 @@ static const unsigned crb_hub_agt[64] = {
0,
};
-static void qlcnic_read_dump_reg(u32 addr, void __iomem *bar0, u32 *data)
-{
- u32 dest;
- void __iomem *window_reg;
-
- dest = addr & 0xFFFF0000;
- window_reg = bar0 + QLCNIC_FW_DUMP_REG1;
- writel(dest, window_reg);
- readl(window_reg);
- window_reg = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
- *data = readl(window_reg);
-}
-
-static void qlcnic_write_dump_reg(u32 addr, void __iomem *bar0, u32 data)
-{
- u32 dest;
- void __iomem *window_reg;
-
- dest = addr & 0xFFFF0000;
- window_reg = bar0 + QLCNIC_FW_DUMP_REG1;
- writel(dest, window_reg);
- readl(window_reg);
- window_reg = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
- writel(data, window_reg);
- readl(window_reg);
-}
-
/* PCI Windowing for DDR regions. */
#define QLCNIC_PCIE_SEM_TIMEOUT 10000
@@ -1088,8 +1061,6 @@ qlcnic_pci_camqm_write_2M(struct qlcnic_adapter *adapter, u64 off, u64 data)
mutex_unlock(&adapter->ahw->mem_lock);
}
-#define MAX_CTL_CHECK 1000
-
int
qlcnic_pci_mem_write_2M(struct qlcnic_adapter *adapter,
u64 off, u64 data)
@@ -1347,460 +1318,3 @@ int qlcnic_config_led(struct qlcnic_adapter *adapter, u32 state, u32 rate)
return rv;
}
-
-/* FW dump related functions */
-static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
-{
- int i;
- u32 addr, data;
- struct __crb *crb = &entry->region.crb;
- void __iomem *base = adapter->ahw->pci_base0;
-
- addr = crb->addr;
-
- for (i = 0; i < crb->no_ops; i++) {
- qlcnic_read_dump_reg(addr, base, &data);
- *buffer++ = cpu_to_le32(addr);
- *buffer++ = cpu_to_le32(data);
- addr += crb->stride;
- }
- return crb->no_ops * 2 * sizeof(u32);
-}
-
-static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
-{
- int i, k, timeout = 0;
- void __iomem *base = adapter->ahw->pci_base0;
- u32 addr, data;
- u8 opcode, no_ops;
- struct __ctrl *ctr = &entry->region.ctrl;
- struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
-
- addr = ctr->addr;
- no_ops = ctr->no_ops;
-
- for (i = 0; i < no_ops; i++) {
- k = 0;
- opcode = 0;
- for (k = 0; k < 8; k++) {
- if (!(ctr->opcode & (1 << k)))
- continue;
- switch (1 << k) {
- case QLCNIC_DUMP_WCRB:
- qlcnic_write_dump_reg(addr, base, ctr->val1);
- break;
- case QLCNIC_DUMP_RWCRB:
- qlcnic_read_dump_reg(addr, base, &data);
- qlcnic_write_dump_reg(addr, base, data);
- break;
- case QLCNIC_DUMP_ANDCRB:
- qlcnic_read_dump_reg(addr, base, &data);
- qlcnic_write_dump_reg(addr, base,
- data & ctr->val2);
- break;
- case QLCNIC_DUMP_ORCRB:
- qlcnic_read_dump_reg(addr, base, &data);
- qlcnic_write_dump_reg(addr, base,
- data | ctr->val3);
- break;
- case QLCNIC_DUMP_POLLCRB:
- while (timeout <= ctr->timeout) {
- qlcnic_read_dump_reg(addr, base, &data);
- if ((data & ctr->val2) == ctr->val1)
- break;
- msleep(1);
- timeout++;
- }
- if (timeout > ctr->timeout) {
- dev_info(&adapter->pdev->dev,
- "Timed out, aborting poll CRB\n");
- return -EINVAL;
- }
- break;
- case QLCNIC_DUMP_RD_SAVE:
- if (ctr->index_a)
- addr = t_hdr->saved_state[ctr->index_a];
- qlcnic_read_dump_reg(addr, base, &data);
- t_hdr->saved_state[ctr->index_v] = data;
- break;
- case QLCNIC_DUMP_WRT_SAVED:
- if (ctr->index_v)
- data = t_hdr->saved_state[ctr->index_v];
- else
- data = ctr->val1;
- if (ctr->index_a)
- addr = t_hdr->saved_state[ctr->index_a];
- qlcnic_write_dump_reg(addr, base, data);
- break;
- case QLCNIC_DUMP_MOD_SAVE_ST:
- data = t_hdr->saved_state[ctr->index_v];
- data <<= ctr->shl_val;
- data >>= ctr->shr_val;
- if (ctr->val2)
- data &= ctr->val2;
- data |= ctr->val3;
- data += ctr->val1;
- t_hdr->saved_state[ctr->index_v] = data;
- break;
- default:
- dev_info(&adapter->pdev->dev,
- "Unknown opcode\n");
- break;
- }
- }
- addr += ctr->stride;
- }
- return 0;
-}
-
-static u32 qlcnic_dump_mux(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
-{
- int loop;
- u32 val, data = 0;
- struct __mux *mux = &entry->region.mux;
- void __iomem *base = adapter->ahw->pci_base0;
-
- val = mux->val;
- for (loop = 0; loop < mux->no_ops; loop++) {
- qlcnic_write_dump_reg(mux->addr, base, val);
- qlcnic_read_dump_reg(mux->read_addr, base, &data);
- *buffer++ = cpu_to_le32(val);
- *buffer++ = cpu_to_le32(data);
- val += mux->val_stride;
- }
- return 2 * mux->no_ops * sizeof(u32);
-}
-
-static u32 qlcnic_dump_que(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
-{
- int i, loop;
- u32 cnt, addr, data, que_id = 0;
- void __iomem *base = adapter->ahw->pci_base0;
- struct __queue *que = &entry->region.que;
-
- addr = que->read_addr;
- cnt = que->read_addr_cnt;
-
- for (loop = 0; loop < que->no_ops; loop++) {
- qlcnic_write_dump_reg(que->sel_addr, base, que_id);
- addr = que->read_addr;
- for (i = 0; i < cnt; i++) {
- qlcnic_read_dump_reg(addr, base, &data);
- *buffer++ = cpu_to_le32(data);
- addr += que->read_addr_stride;
- }
- que_id += que->stride;
- }
- return que->no_ops * cnt * sizeof(u32);
-}
-
-static u32 qlcnic_dump_ocm(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
-{
- int i;
- u32 data;
- void __iomem *addr;
- struct __ocm *ocm = &entry->region.ocm;
-
- addr = adapter->ahw->pci_base0 + ocm->read_addr;
- for (i = 0; i < ocm->no_ops; i++) {
- data = readl(addr);
- *buffer++ = cpu_to_le32(data);
- addr += ocm->read_addr_stride;
- }
- return ocm->no_ops * sizeof(u32);
-}
-
-static u32 qlcnic_read_rom(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
-{
- int i, count = 0;
- u32 fl_addr, size, val, lck_val, addr;
- struct __mem *rom = &entry->region.mem;
- void __iomem *base = adapter->ahw->pci_base0;
-
- fl_addr = rom->addr;
- size = rom->size/4;
-lock_try:
- lck_val = readl(base + QLCNIC_FLASH_SEM2_LK);
- if (!lck_val && count < MAX_CTL_CHECK) {
- msleep(10);
- count++;
- goto lock_try;
- }
- writel(adapter->ahw->pci_func, (base + QLCNIC_FLASH_LOCK_ID));
- for (i = 0; i < size; i++) {
- addr = fl_addr & 0xFFFF0000;
- qlcnic_write_dump_reg(FLASH_ROM_WINDOW, base, addr);
- addr = LSW(fl_addr) + FLASH_ROM_DATA;
- qlcnic_read_dump_reg(addr, base, &val);
- fl_addr += 4;
- *buffer++ = cpu_to_le32(val);
- }
- readl(base + QLCNIC_FLASH_SEM2_ULK);
- return rom->size;
-}
-
-static u32 qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
-{
- int i;
- u32 cnt, val, data, addr;
- void __iomem *base = adapter->ahw->pci_base0;
- struct __cache *l1 = &entry->region.cache;
-
- val = l1->init_tag_val;
-
- for (i = 0; i < l1->no_ops; i++) {
- qlcnic_write_dump_reg(l1->addr, base, val);
- qlcnic_write_dump_reg(l1->ctrl_addr, base, LSW(l1->ctrl_val));
- addr = l1->read_addr;
- cnt = l1->read_addr_num;
- while (cnt) {
- qlcnic_read_dump_reg(addr, base, &data);
- *buffer++ = cpu_to_le32(data);
- addr += l1->read_addr_stride;
- cnt--;
- }
- val += l1->stride;
- }
- return l1->no_ops * l1->read_addr_num * sizeof(u32);
-}
-
-static u32 qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
-{
- int i;
- u32 cnt, val, data, addr;
- u8 poll_mask, poll_to, time_out = 0;
- void __iomem *base = adapter->ahw->pci_base0;
- struct __cache *l2 = &entry->region.cache;
-
- val = l2->init_tag_val;
- poll_mask = LSB(MSW(l2->ctrl_val));
- poll_to = MSB(MSW(l2->ctrl_val));
-
- for (i = 0; i < l2->no_ops; i++) {
- qlcnic_write_dump_reg(l2->addr, base, val);
- if (LSW(l2->ctrl_val))
- qlcnic_write_dump_reg(l2->ctrl_addr, base,
- LSW(l2->ctrl_val));
- if (!poll_mask)
- goto skip_poll;
- do {
- qlcnic_read_dump_reg(l2->ctrl_addr, base, &data);
- if (!(data & poll_mask))
- break;
- msleep(1);
- time_out++;
- } while (time_out <= poll_to);
-
- if (time_out > poll_to) {
- dev_err(&adapter->pdev->dev,
- "Timeout exceeded in %s, aborting dump\n",
- __func__);
- return -EINVAL;
- }
-skip_poll:
- addr = l2->read_addr;
- cnt = l2->read_addr_num;
- while (cnt) {
- qlcnic_read_dump_reg(addr, base, &data);
- *buffer++ = cpu_to_le32(data);
- addr += l2->read_addr_stride;
- cnt--;
- }
- val += l2->stride;
- }
- return l2->no_ops * l2->read_addr_num * sizeof(u32);
-}
-
-static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
-{
- u32 addr, data, test, ret = 0;
- int i, reg_read;
- struct __mem *mem = &entry->region.mem;
- void __iomem *base = adapter->ahw->pci_base0;
-
- reg_read = mem->size;
- addr = mem->addr;
- /* check for data size of multiple of 16 and 16 byte alignment */
- if ((addr & 0xf) || (reg_read%16)) {
- dev_info(&adapter->pdev->dev,
- "Unaligned memory addr:0x%x size:0x%x\n",
- addr, reg_read);
- return -EINVAL;
- }
-
- mutex_lock(&adapter->ahw->mem_lock);
-
- while (reg_read != 0) {
- qlcnic_write_dump_reg(MIU_TEST_ADDR_LO, base, addr);
- qlcnic_write_dump_reg(MIU_TEST_ADDR_HI, base, 0);
- qlcnic_write_dump_reg(MIU_TEST_CTR, base,
- TA_CTL_ENABLE | TA_CTL_START);
-
- for (i = 0; i < MAX_CTL_CHECK; i++) {
- qlcnic_read_dump_reg(MIU_TEST_CTR, base, &test);
- if (!(test & TA_CTL_BUSY))
- break;
- }
- if (i == MAX_CTL_CHECK) {
- if (printk_ratelimit()) {
- dev_err(&adapter->pdev->dev,
- "failed to read through agent\n");
- ret = -EINVAL;
- goto out;
- }
- }
- for (i = 0; i < 4; i++) {
- qlcnic_read_dump_reg(MIU_TEST_READ_DATA[i], base,
- &data);
- *buffer++ = cpu_to_le32(data);
- }
- addr += 16;
- reg_read -= 16;
- ret += 16;
- }
-out:
- mutex_unlock(&adapter->ahw->mem_lock);
- return mem->size;
-}
-
-static u32 qlcnic_dump_nop(struct qlcnic_adapter *adapter,
- struct qlcnic_dump_entry *entry, __le32 *buffer)
-{
- entry->hdr.flags |= QLCNIC_DUMP_SKIP;
- return 0;
-}
-
-static const struct qlcnic_dump_operations fw_dump_ops[] = {
- { QLCNIC_DUMP_NOP, qlcnic_dump_nop },
- { QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb },
- { QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux },
- { QLCNIC_DUMP_QUEUE, qlcnic_dump_que },
- { QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom },
- { QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm },
- { QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl },
- { QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache },
- { QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache },
- { QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache },
- { QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache },
- { QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache },
- { QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache },
- { QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache },
- { QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache },
- { QLCNIC_DUMP_READ_ROM, qlcnic_read_rom },
- { QLCNIC_DUMP_READ_MEM, qlcnic_read_memory },
- { QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl },
- { QLCNIC_DUMP_TLHDR, qlcnic_dump_nop },
- { QLCNIC_DUMP_RDEND, qlcnic_dump_nop },
-};
-
-/* Walk the template and collect dump for each entry in the dump template */
-static int
-qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry,
- u32 size)
-{
- int ret = 1;
- if (size != entry->hdr.cap_size) {
- dev_info(dev,
- "Invalidate dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
- entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size);
- dev_info(dev, "Aborting further dump capture\n");
- ret = 0;
- }
- return ret;
-}
-
-int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
-{
- __le32 *buffer;
- char mesg[64];
- char *msg[] = {mesg, NULL};
- int i, k, ops_cnt, ops_index, dump_size = 0;
- u32 entry_offset, dump, no_entries, buf_offset = 0;
- struct qlcnic_dump_entry *entry;
- struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
- struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
-
- if (fw_dump->clr) {
- dev_info(&adapter->pdev->dev,
- "Previous dump not cleared, not capturing dump\n");
- return -EIO;
- }
- /* Calculate the size for dump data area only */
- for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
- if (i & tmpl_hdr->drv_cap_mask)
- dump_size += tmpl_hdr->cap_sizes[k];
- if (!dump_size)
- return -EIO;
-
- fw_dump->data = vzalloc(dump_size);
- if (!fw_dump->data) {
- dev_info(&adapter->pdev->dev,
- "Unable to allocate (%d KB) for fw dump\n",
- dump_size/1024);
- return -ENOMEM;
- }
- buffer = fw_dump->data;
- fw_dump->size = dump_size;
- no_entries = tmpl_hdr->num_entries;
- ops_cnt = ARRAY_SIZE(fw_dump_ops);
- entry_offset = tmpl_hdr->offset;
- tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
- tmpl_hdr->sys_info[1] = adapter->fw_version;
-
- for (i = 0; i < no_entries; i++) {
- entry = (void *)tmpl_hdr + entry_offset;
- if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
- entry->hdr.flags |= QLCNIC_DUMP_SKIP;
- entry_offset += entry->hdr.offset;
- continue;
- }
- /* Find the handler for this entry */
- ops_index = 0;
- while (ops_index < ops_cnt) {
- if (entry->hdr.type == fw_dump_ops[ops_index].opcode)
- break;
- ops_index++;
- }
- if (ops_index == ops_cnt) {
- dev_info(&adapter->pdev->dev,
- "Invalid entry type %d, exiting dump\n",
- entry->hdr.type);
- goto error;
- }
- /* Collect dump for this entry */
- dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
- if (dump && !qlcnic_valid_dump_entry(&adapter->pdev->dev, entry,
- dump))
- entry->hdr.flags |= QLCNIC_DUMP_SKIP;
- buf_offset += entry->hdr.cap_size;
- entry_offset += entry->hdr.offset;
- buffer = fw_dump->data + buf_offset;
- }
- if (dump_size != buf_offset) {
- dev_info(&adapter->pdev->dev,
- "Captured(%d) and expected size(%d) do not match\n",
- buf_offset, dump_size);
- goto error;
- } else {
- fw_dump->clr = 1;
- snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
- adapter->netdev->name);
- dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n",
- fw_dump->size);
- /* Send a udev event to notify availability of FW dump */
- kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg);
- return 0;
- }
-error:
- vfree(fw_dump->data);
- return -EINVAL;
-}
diff --git a/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
new file mode 100644
index 0000000..5e22c62
--- /dev/null
+++ b/drivers/net/ethernet/qlogic/qlcnic/qlcnic_minidump.c
@@ -0,0 +1,629 @@
+#include "qlcnic.h"
+#include "qlcnic_hdr.h"
+
+#include <net/ip.h>
+
+#define QLCNIC_DUMP_WCRB BIT_0
+#define QLCNIC_DUMP_RWCRB BIT_1
+#define QLCNIC_DUMP_ANDCRB BIT_2
+#define QLCNIC_DUMP_ORCRB BIT_3
+#define QLCNIC_DUMP_POLLCRB BIT_4
+#define QLCNIC_DUMP_RD_SAVE BIT_5
+#define QLCNIC_DUMP_WRT_SAVED BIT_6
+#define QLCNIC_DUMP_MOD_SAVE_ST BIT_7
+#define QLCNIC_DUMP_SKIP BIT_7
+
+#define QLCNIC_DUMP_MASK_MAX 0xff
+
+struct qlcnic_common_entry_hdr {
+ u32 type;
+ u32 offset;
+ u32 cap_size;
+ u8 mask;
+ u8 rsvd[2];
+ u8 flags;
+} __packed;
+
+struct __crb {
+ u32 addr;
+ u8 stride;
+ u8 rsvd1[3];
+ u32 data_size;
+ u32 no_ops;
+ u32 rsvd2[4];
+} __packed;
+
+struct __ctrl {
+ u32 addr;
+ u8 stride;
+ u8 index_a;
+ u16 timeout;
+ u32 data_size;
+ u32 no_ops;
+ u8 opcode;
+ u8 index_v;
+ u8 shl_val;
+ u8 shr_val;
+ u32 val1;
+ u32 val2;
+ u32 val3;
+} __packed;
+
+struct __cache {
+ u32 addr;
+ u16 stride;
+ u16 init_tag_val;
+ u32 size;
+ u32 no_ops;
+ u32 ctrl_addr;
+ u32 ctrl_val;
+ u32 read_addr;
+ u8 read_addr_stride;
+ u8 read_addr_num;
+ u8 rsvd1[2];
+} __packed;
+
+struct __ocm {
+ u8 rsvd[8];
+ u32 size;
+ u32 no_ops;
+ u8 rsvd1[8];
+ u32 read_addr;
+ u32 read_addr_stride;
+} __packed;
+
+struct __mem {
+ u8 rsvd[24];
+ u32 addr;
+ u32 size;
+} __packed;
+
+struct __mux {
+ u32 addr;
+ u8 rsvd[4];
+ u32 size;
+ u32 no_ops;
+ u32 val;
+ u32 val_stride;
+ u32 read_addr;
+ u8 rsvd2[4];
+} __packed;
+
+struct __queue {
+ u32 sel_addr;
+ u16 stride;
+ u8 rsvd[2];
+ u32 size;
+ u32 no_ops;
+ u8 rsvd2[8];
+ u32 read_addr;
+ u8 read_addr_stride;
+ u8 read_addr_cnt;
+ u8 rsvd3[2];
+} __packed;
+
+struct qlcnic_dump_entry {
+ struct qlcnic_common_entry_hdr hdr;
+ union {
+ struct __crb crb;
+ struct __cache cache;
+ struct __ocm ocm;
+ struct __mem mem;
+ struct __mux mux;
+ struct __queue que;
+ struct __ctrl ctrl;
+ } region;
+} __packed;
+
+enum op_codes {
+ QLCNIC_DUMP_NOP = 0,
+ QLCNIC_DUMP_READ_CRB = 1,
+ QLCNIC_DUMP_READ_MUX = 2,
+ QLCNIC_DUMP_QUEUE = 3,
+ QLCNIC_DUMP_BRD_CONFIG = 4,
+ QLCNIC_DUMP_READ_OCM = 6,
+ QLCNIC_DUMP_PEG_REG = 7,
+ QLCNIC_DUMP_L1_DTAG = 8,
+ QLCNIC_DUMP_L1_ITAG = 9,
+ QLCNIC_DUMP_L1_DATA = 11,
+ QLCNIC_DUMP_L1_INST = 12,
+ QLCNIC_DUMP_L2_DTAG = 21,
+ QLCNIC_DUMP_L2_ITAG = 22,
+ QLCNIC_DUMP_L2_DATA = 23,
+ QLCNIC_DUMP_L2_INST = 24,
+ QLCNIC_DUMP_READ_ROM = 71,
+ QLCNIC_DUMP_READ_MEM = 72,
+ QLCNIC_DUMP_READ_CTRL = 98,
+ QLCNIC_DUMP_TLHDR = 99,
+ QLCNIC_DUMP_RDEND = 255
+};
+
+struct qlcnic_dump_operations {
+ enum op_codes opcode;
+ u32 (*handler)(struct qlcnic_adapter *, struct qlcnic_dump_entry *,
+ __le32 *);
+};
+
+static void qlcnic_read_dump_reg(u32 addr, void __iomem *bar0, u32 *data)
+{
+ u32 dest;
+ void __iomem *window_reg;
+
+ dest = addr & 0xFFFF0000;
+ window_reg = bar0 + QLCNIC_FW_DUMP_REG1;
+ writel(dest, window_reg);
+ readl(window_reg);
+ window_reg = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
+ *data = readl(window_reg);
+}
+
+static void qlcnic_write_dump_reg(u32 addr, void __iomem *bar0, u32 data)
+{
+ u32 dest;
+ void __iomem *window_reg;
+
+ dest = addr & 0xFFFF0000;
+ window_reg = bar0 + QLCNIC_FW_DUMP_REG1;
+ writel(dest, window_reg);
+ readl(window_reg);
+ window_reg = bar0 + QLCNIC_FW_DUMP_REG2 + LSW(addr);
+ writel(data, window_reg);
+ readl(window_reg);
+}
+
+/* FW dump related functions */
+static u32 qlcnic_dump_crb(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ int i;
+ u32 addr, data;
+ struct __crb *crb = &entry->region.crb;
+ void __iomem *base = adapter->ahw->pci_base0;
+
+ addr = crb->addr;
+
+ for (i = 0; i < crb->no_ops; i++) {
+ qlcnic_read_dump_reg(addr, base, &data);
+ *buffer++ = cpu_to_le32(addr);
+ *buffer++ = cpu_to_le32(data);
+ addr += crb->stride;
+ }
+ return crb->no_ops * 2 * sizeof(u32);
+}
+
+static u32 qlcnic_dump_ctrl(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ int i, k, timeout = 0;
+ void __iomem *base = adapter->ahw->pci_base0;
+ u32 addr, data;
+ u8 opcode, no_ops;
+ struct __ctrl *ctr = &entry->region.ctrl;
+ struct qlcnic_dump_template_hdr *t_hdr = adapter->ahw->fw_dump.tmpl_hdr;
+
+ addr = ctr->addr;
+ no_ops = ctr->no_ops;
+
+ for (i = 0; i < no_ops; i++) {
+ k = 0;
+ opcode = 0;
+ for (k = 0; k < 8; k++) {
+ if (!(ctr->opcode & (1 << k)))
+ continue;
+ switch (1 << k) {
+ case QLCNIC_DUMP_WCRB:
+ qlcnic_write_dump_reg(addr, base, ctr->val1);
+ break;
+ case QLCNIC_DUMP_RWCRB:
+ qlcnic_read_dump_reg(addr, base, &data);
+ qlcnic_write_dump_reg(addr, base, data);
+ break;
+ case QLCNIC_DUMP_ANDCRB:
+ qlcnic_read_dump_reg(addr, base, &data);
+ qlcnic_write_dump_reg(addr, base,
+ data & ctr->val2);
+ break;
+ case QLCNIC_DUMP_ORCRB:
+ qlcnic_read_dump_reg(addr, base, &data);
+ qlcnic_write_dump_reg(addr, base,
+ data | ctr->val3);
+ break;
+ case QLCNIC_DUMP_POLLCRB:
+ while (timeout <= ctr->timeout) {
+ qlcnic_read_dump_reg(addr, base, &data);
+ if ((data & ctr->val2) == ctr->val1)
+ break;
+ msleep(1);
+ timeout++;
+ }
+ if (timeout > ctr->timeout) {
+ dev_info(&adapter->pdev->dev,
+ "Timed out, aborting poll CRB\n");
+ return -EINVAL;
+ }
+ break;
+ case QLCNIC_DUMP_RD_SAVE:
+ if (ctr->index_a)
+ addr = t_hdr->saved_state[ctr->index_a];
+ qlcnic_read_dump_reg(addr, base, &data);
+ t_hdr->saved_state[ctr->index_v] = data;
+ break;
+ case QLCNIC_DUMP_WRT_SAVED:
+ if (ctr->index_v)
+ data = t_hdr->saved_state[ctr->index_v];
+ else
+ data = ctr->val1;
+ if (ctr->index_a)
+ addr = t_hdr->saved_state[ctr->index_a];
+ qlcnic_write_dump_reg(addr, base, data);
+ break;
+ case QLCNIC_DUMP_MOD_SAVE_ST:
+ data = t_hdr->saved_state[ctr->index_v];
+ data <<= ctr->shl_val;
+ data >>= ctr->shr_val;
+ if (ctr->val2)
+ data &= ctr->val2;
+ data |= ctr->val3;
+ data += ctr->val1;
+ t_hdr->saved_state[ctr->index_v] = data;
+ break;
+ default:
+ dev_info(&adapter->pdev->dev,
+ "Unknown opcode\n");
+ break;
+ }
+ }
+ addr += ctr->stride;
+ }
+ return 0;
+}
+
+static u32 qlcnic_dump_mux(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ int loop;
+ u32 val, data = 0;
+ struct __mux *mux = &entry->region.mux;
+ void __iomem *base = adapter->ahw->pci_base0;
+
+ val = mux->val;
+ for (loop = 0; loop < mux->no_ops; loop++) {
+ qlcnic_write_dump_reg(mux->addr, base, val);
+ qlcnic_read_dump_reg(mux->read_addr, base, &data);
+ *buffer++ = cpu_to_le32(val);
+ *buffer++ = cpu_to_le32(data);
+ val += mux->val_stride;
+ }
+ return 2 * mux->no_ops * sizeof(u32);
+}
+
+static u32 qlcnic_dump_que(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ int i, loop;
+ u32 cnt, addr, data, que_id = 0;
+ void __iomem *base = adapter->ahw->pci_base0;
+ struct __queue *que = &entry->region.que;
+
+ addr = que->read_addr;
+ cnt = que->read_addr_cnt;
+
+ for (loop = 0; loop < que->no_ops; loop++) {
+ qlcnic_write_dump_reg(que->sel_addr, base, que_id);
+ addr = que->read_addr;
+ for (i = 0; i < cnt; i++) {
+ qlcnic_read_dump_reg(addr, base, &data);
+ *buffer++ = cpu_to_le32(data);
+ addr += que->read_addr_stride;
+ }
+ que_id += que->stride;
+ }
+ return que->no_ops * cnt * sizeof(u32);
+}
+
+static u32 qlcnic_dump_ocm(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ int i;
+ u32 data;
+ void __iomem *addr;
+ struct __ocm *ocm = &entry->region.ocm;
+
+ addr = adapter->ahw->pci_base0 + ocm->read_addr;
+ for (i = 0; i < ocm->no_ops; i++) {
+ data = readl(addr);
+ *buffer++ = cpu_to_le32(data);
+ addr += ocm->read_addr_stride;
+ }
+ return ocm->no_ops * sizeof(u32);
+}
+
+static u32 qlcnic_read_rom(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ int i, count = 0;
+ u32 fl_addr, size, val, lck_val, addr;
+ struct __mem *rom = &entry->region.mem;
+ void __iomem *base = adapter->ahw->pci_base0;
+
+ fl_addr = rom->addr;
+ size = rom->size/4;
+lock_try:
+ lck_val = readl(base + QLCNIC_FLASH_SEM2_LK);
+ if (!lck_val && count < MAX_CTL_CHECK) {
+ msleep(10);
+ count++;
+ goto lock_try;
+ }
+ writel(adapter->ahw->pci_func, (base + QLCNIC_FLASH_LOCK_ID));
+ for (i = 0; i < size; i++) {
+ addr = fl_addr & 0xFFFF0000;
+ qlcnic_write_dump_reg(FLASH_ROM_WINDOW, base, addr);
+ addr = LSW(fl_addr) + FLASH_ROM_DATA;
+ qlcnic_read_dump_reg(addr, base, &val);
+ fl_addr += 4;
+ *buffer++ = cpu_to_le32(val);
+ }
+ readl(base + QLCNIC_FLASH_SEM2_ULK);
+ return rom->size;
+}
+
+static u32 qlcnic_dump_l1_cache(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ int i;
+ u32 cnt, val, data, addr;
+ void __iomem *base = adapter->ahw->pci_base0;
+ struct __cache *l1 = &entry->region.cache;
+
+ val = l1->init_tag_val;
+
+ for (i = 0; i < l1->no_ops; i++) {
+ qlcnic_write_dump_reg(l1->addr, base, val);
+ qlcnic_write_dump_reg(l1->ctrl_addr, base, LSW(l1->ctrl_val));
+ addr = l1->read_addr;
+ cnt = l1->read_addr_num;
+ while (cnt) {
+ qlcnic_read_dump_reg(addr, base, &data);
+ *buffer++ = cpu_to_le32(data);
+ addr += l1->read_addr_stride;
+ cnt--;
+ }
+ val += l1->stride;
+ }
+ return l1->no_ops * l1->read_addr_num * sizeof(u32);
+}
+
+static u32 qlcnic_dump_l2_cache(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ int i;
+ u32 cnt, val, data, addr;
+ u8 poll_mask, poll_to, time_out = 0;
+ void __iomem *base = adapter->ahw->pci_base0;
+ struct __cache *l2 = &entry->region.cache;
+
+ val = l2->init_tag_val;
+ poll_mask = LSB(MSW(l2->ctrl_val));
+ poll_to = MSB(MSW(l2->ctrl_val));
+
+ for (i = 0; i < l2->no_ops; i++) {
+ qlcnic_write_dump_reg(l2->addr, base, val);
+ if (LSW(l2->ctrl_val))
+ qlcnic_write_dump_reg(l2->ctrl_addr, base,
+ LSW(l2->ctrl_val));
+ if (!poll_mask)
+ goto skip_poll;
+ do {
+ qlcnic_read_dump_reg(l2->ctrl_addr, base, &data);
+ if (!(data & poll_mask))
+ break;
+ msleep(1);
+ time_out++;
+ } while (time_out <= poll_to);
+
+ if (time_out > poll_to) {
+ dev_err(&adapter->pdev->dev,
+ "Timeout exceeded in %s, aborting dump\n",
+ __func__);
+ return -EINVAL;
+ }
+skip_poll:
+ addr = l2->read_addr;
+ cnt = l2->read_addr_num;
+ while (cnt) {
+ qlcnic_read_dump_reg(addr, base, &data);
+ *buffer++ = cpu_to_le32(data);
+ addr += l2->read_addr_stride;
+ cnt--;
+ }
+ val += l2->stride;
+ }
+ return l2->no_ops * l2->read_addr_num * sizeof(u32);
+}
+
+static u32 qlcnic_read_memory(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ u32 addr, data, test, ret = 0;
+ int i, reg_read;
+ struct __mem *mem = &entry->region.mem;
+ void __iomem *base = adapter->ahw->pci_base0;
+
+ reg_read = mem->size;
+ addr = mem->addr;
+ /* check for data size of multiple of 16 and 16 byte alignment */
+ if ((addr & 0xf) || (reg_read%16)) {
+ dev_info(&adapter->pdev->dev,
+ "Unaligned memory addr:0x%x size:0x%x\n",
+ addr, reg_read);
+ return -EINVAL;
+ }
+
+ mutex_lock(&adapter->ahw->mem_lock);
+
+ while (reg_read != 0) {
+ qlcnic_write_dump_reg(MIU_TEST_ADDR_LO, base, addr);
+ qlcnic_write_dump_reg(MIU_TEST_ADDR_HI, base, 0);
+ qlcnic_write_dump_reg(MIU_TEST_CTR, base,
+ TA_CTL_ENABLE | TA_CTL_START);
+
+ for (i = 0; i < MAX_CTL_CHECK; i++) {
+ qlcnic_read_dump_reg(MIU_TEST_CTR, base, &test);
+ if (!(test & TA_CTL_BUSY))
+ break;
+ }
+ if (i == MAX_CTL_CHECK) {
+ if (printk_ratelimit()) {
+ dev_err(&adapter->pdev->dev,
+ "failed to read through agent\n");
+ ret = -EINVAL;
+ goto out;
+ }
+ }
+ for (i = 0; i < 4; i++) {
+ qlcnic_read_dump_reg(MIU_TEST_READ_DATA[i], base,
+ &data);
+ *buffer++ = cpu_to_le32(data);
+ }
+ addr += 16;
+ reg_read -= 16;
+ ret += 16;
+ }
+out:
+ mutex_unlock(&adapter->ahw->mem_lock);
+ return mem->size;
+}
+
+static u32 qlcnic_dump_nop(struct qlcnic_adapter *adapter,
+ struct qlcnic_dump_entry *entry, __le32 *buffer)
+{
+ entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+ return 0;
+}
+
+static const struct qlcnic_dump_operations fw_dump_ops[] = {
+ { QLCNIC_DUMP_NOP, qlcnic_dump_nop },
+ { QLCNIC_DUMP_READ_CRB, qlcnic_dump_crb },
+ { QLCNIC_DUMP_READ_MUX, qlcnic_dump_mux },
+ { QLCNIC_DUMP_QUEUE, qlcnic_dump_que },
+ { QLCNIC_DUMP_BRD_CONFIG, qlcnic_read_rom },
+ { QLCNIC_DUMP_READ_OCM, qlcnic_dump_ocm },
+ { QLCNIC_DUMP_PEG_REG, qlcnic_dump_ctrl },
+ { QLCNIC_DUMP_L1_DTAG, qlcnic_dump_l1_cache },
+ { QLCNIC_DUMP_L1_ITAG, qlcnic_dump_l1_cache },
+ { QLCNIC_DUMP_L1_DATA, qlcnic_dump_l1_cache },
+ { QLCNIC_DUMP_L1_INST, qlcnic_dump_l1_cache },
+ { QLCNIC_DUMP_L2_DTAG, qlcnic_dump_l2_cache },
+ { QLCNIC_DUMP_L2_ITAG, qlcnic_dump_l2_cache },
+ { QLCNIC_DUMP_L2_DATA, qlcnic_dump_l2_cache },
+ { QLCNIC_DUMP_L2_INST, qlcnic_dump_l2_cache },
+ { QLCNIC_DUMP_READ_ROM, qlcnic_read_rom },
+ { QLCNIC_DUMP_READ_MEM, qlcnic_read_memory },
+ { QLCNIC_DUMP_READ_CTRL, qlcnic_dump_ctrl },
+ { QLCNIC_DUMP_TLHDR, qlcnic_dump_nop },
+ { QLCNIC_DUMP_RDEND, qlcnic_dump_nop },
+};
+
+/* Walk the template and collect dump for each entry in the dump template */
+static int
+qlcnic_valid_dump_entry(struct device *dev, struct qlcnic_dump_entry *entry,
+ u32 size)
+{
+ int ret = 1;
+ if (size != entry->hdr.cap_size) {
+ dev_info(dev,
+ "Invalidate dump, Type:%d\tMask:%d\tSize:%dCap_size:%d\n",
+ entry->hdr.type, entry->hdr.mask, size, entry->hdr.cap_size);
+ dev_info(dev, "Aborting further dump capture\n");
+ ret = 0;
+ }
+ return ret;
+}
+
+int qlcnic_dump_fw(struct qlcnic_adapter *adapter)
+{
+ __le32 *buffer;
+ char mesg[64];
+ char *msg[] = {mesg, NULL};
+ int i, k, ops_cnt, ops_index, dump_size = 0;
+ u32 entry_offset, dump, no_entries, buf_offset = 0;
+ struct qlcnic_dump_entry *entry;
+ struct qlcnic_fw_dump *fw_dump = &adapter->ahw->fw_dump;
+ struct qlcnic_dump_template_hdr *tmpl_hdr = fw_dump->tmpl_hdr;
+
+ if (fw_dump->clr) {
+ dev_info(&adapter->pdev->dev,
+ "Previous dump not cleared, not capturing dump\n");
+ return -EIO;
+ }
+ /* Calculate the size for dump data area only */
+ for (i = 2, k = 1; (i & QLCNIC_DUMP_MASK_MAX); i <<= 1, k++)
+ if (i & tmpl_hdr->drv_cap_mask)
+ dump_size += tmpl_hdr->cap_sizes[k];
+ if (!dump_size)
+ return -EIO;
+
+ fw_dump->data = vzalloc(dump_size);
+ if (!fw_dump->data) {
+ dev_info(&adapter->pdev->dev,
+ "Unable to allocate (%d KB) for fw dump\n",
+ dump_size/1024);
+ return -ENOMEM;
+ }
+ buffer = fw_dump->data;
+ fw_dump->size = dump_size;
+ no_entries = tmpl_hdr->num_entries;
+ ops_cnt = ARRAY_SIZE(fw_dump_ops);
+ entry_offset = tmpl_hdr->offset;
+ tmpl_hdr->sys_info[0] = QLCNIC_DRIVER_VERSION;
+ tmpl_hdr->sys_info[1] = adapter->fw_version;
+
+ for (i = 0; i < no_entries; i++) {
+ entry = (void *)tmpl_hdr + entry_offset;
+ if (!(entry->hdr.mask & tmpl_hdr->drv_cap_mask)) {
+ entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+ entry_offset += entry->hdr.offset;
+ continue;
+ }
+ /* Find the handler for this entry */
+ ops_index = 0;
+ while (ops_index < ops_cnt) {
+ if (entry->hdr.type == fw_dump_ops[ops_index].opcode)
+ break;
+ ops_index++;
+ }
+ if (ops_index == ops_cnt) {
+ dev_info(&adapter->pdev->dev,
+ "Invalid entry type %d, exiting dump\n",
+ entry->hdr.type);
+ goto error;
+ }
+ /* Collect dump for this entry */
+ dump = fw_dump_ops[ops_index].handler(adapter, entry, buffer);
+ if (dump && !qlcnic_valid_dump_entry(&adapter->pdev->dev, entry,
+ dump))
+ entry->hdr.flags |= QLCNIC_DUMP_SKIP;
+ buf_offset += entry->hdr.cap_size;
+ entry_offset += entry->hdr.offset;
+ buffer = fw_dump->data + buf_offset;
+ }
+ if (dump_size != buf_offset) {
+ dev_info(&adapter->pdev->dev,
+ "Captured(%d) and expected size(%d) do not match\n",
+ buf_offset, dump_size);
+ goto error;
+ } else {
+ fw_dump->clr = 1;
+ snprintf(mesg, sizeof(mesg), "FW_DUMP=%s",
+ adapter->netdev->name);
+ dev_info(&adapter->pdev->dev, "Dump data, %d bytes captured\n",
+ fw_dump->size);
+ /* Send a udev event to notify availability of FW dump */
+ kobject_uevent_env(&adapter->pdev->dev.kobj, KOBJ_CHANGE, msg);
+ return 0;
+ }
+error:
+ vfree(fw_dump->data);
+ return -EINVAL;
+}
--
1.7.1
^ permalink raw reply related
* Re: Move an interface to init_ne
From: Renato Westphal @ 2012-11-28 15:01 UTC (permalink / raw)
To: David Shwatrz; +Cc: netdev, Eric W. Biederman
In-Reply-To: <CAJJAcodehJ3x2ZjOuoaV=KrWHH23013b3O20nqh0E1smFvFpHw@mail.gmail.com>
2012/11/28 David Shwatrz <dshwatrz@gmail.com>:
> Hello,
>
> How to I move an interface back to the original namespace ?
> I created three namespaces:
>
> ip netns add namespace1
> ip netns add namespace2
> ip netns add namespace3
>
> And move eth0 to namespace1:
> ip link set eth0 netns namespace1
>
> How do I return it back to the original, default network namespace ? (init_net)
# ip link set eth0 netns 1
The 'netns' argument can be either a netns name or a process ID (pid).
Providing a pid, you'll be moving the interface to the netns of the
given process, which is the initial network namespace for pid = 1 (the
init process).
--
Renato Westphal
^ permalink raw reply
* Wireless regression in workqueue: use mod_delayed_work() instead of __cancel + queue
From: Anders Kaseorg @ 2012-11-28 15:13 UTC (permalink / raw)
To: Tejun Heo, Herbert Xu, John W. Linville
Cc: netdev-u79uwXL29TY76Z2rM5mHXA,
linux-wireless-u79uwXL29TY76Z2rM5mHXA, linux-kernel-OBmyj6YDURU
My Intel 6250 wireless card (iwldvm) can no longer associate with a
WPA-Enterprise network (PEAP-MSCHAPv2). To my surprise, I bisected this
regression to commit e7c2f967445dd2041f0f8e3179cca22bb8bb7f79,
workqueue: use mod_delayed_work() instead of __cancel + queue.
A bunch of logs collected by Ubuntu apport are in this bug report:
https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1083980
How can I help to debug this?
I see that someone else reported another regression with the same commit
last week, although this looks unrelated at first glance:
http://thread.gmane.org/gmane.linux.kernel/1395938
Anders
--
To unsubscribe from this list: send the line "unsubscribe linux-wireless" in
the body of a message to majordomo-u79uwXL29TY76Z2rM5mHXA@public.gmane.org
More majordomo info at http://vger.kernel.org/majordomo-info.html
^ permalink raw reply
* Re: Wireless regression in workqueue: use mod_delayed_work() instead of __cancel + queue
From: Anders Kaseorg @ 2012-11-28 15:17 UTC (permalink / raw)
To: Tejun Heo, Herbert Xu, John W. Linville
Cc: netdev, linux-wireless, linux-kernel
In-Reply-To: <alpine.DEB.2.00.1211280953350.26602@dr-wily.mit.edu>
On Wed, 28 Nov 2012, Anders Kaseorg wrote:
> My Intel 6250 wireless card (iwldvm) can no longer associate with a
> WPA-Enterprise network (PEAP-MSCHAPv2). To my surprise, I bisected this
> regression to commit e7c2f967445dd2041f0f8e3179cca22bb8bb7f79,
> workqueue: use mod_delayed_work() instead of __cancel + queue.
>
> A bunch of logs collected by Ubuntu apport are in this bug report:
> https://bugs.launchpad.net/ubuntu/+source/linux/+bug/1083980
>
> How can I help to debug this?
>
> I see that someone else reported another regression with the same commit
> last week, although this looks unrelated at first glance:
> http://thread.gmane.org/gmane.linux.kernel/1395938
>
> Anders
(Oops, re-sending to fix a typo in the LKML address.)
Anders
^ permalink raw reply
* [PATCH] sctp: Error in calculation of RTTvar
From: vyasevich @ 2012-11-28 15:18 UTC (permalink / raw)
To: netdev; +Cc: davem
From: Schoch Christian <e0326715@student.tuwien.ac.at>
The calculation of RTTVAR involves the subtraction of two unsigned
numbers which
may causes rollover and results in very high values of RTTVAR when RTT > SRTT.
With this patch it is possible to set RTOmin = 1 to get the minimum of RTO at
4 times the clock granularity.
Change Notes:
v2)
*Replaced abs() by abs64() and long by __s64, changed patch
description.
Signed-off-by: Christian Schoch <e0326715@student.tuwien.ac.at>
CC: Vlad Yasevich <vyasevich@gmail.com>
CC: Sridhar Samudrala <sri@us.ibm.com>
CC: Neil Horman <nhorman@tuxdriver.com>
CC: linux-sctp@vger.kernel.org
Acked-by: Vlad Yasevich <vyasevich@gmail.com>
Acked-by: Neil Horman <nhorman@tuxdriver.com>
---
net/sctp/transport.c | 2 +-
1 files changed, 1 insertions(+), 1 deletions(-)
diff --git a/net/sctp/transport.c b/net/sctp/transport.c
index 953c21e..206cf52 100644
--- a/net/sctp/transport.c
+++ b/net/sctp/transport.c
@@ -331,7 +331,7 @@ void sctp_transport_update_rto(struct sctp_transport *tp, __u32 rtt)
* 1/8, rto_alpha would be expressed as 3.
*/
tp->rttvar = tp->rttvar - (tp->rttvar >> net->sctp.rto_beta)
- + ((abs(tp->srtt - rtt)) >> net->sctp.rto_beta);
+ + (((__u32)abs64((__s64)tp->srtt - (__s64)rtt)) >> net->sctp.rto_beta);
tp->srtt = tp->srtt - (tp->srtt >> net->sctp.rto_alpha)
+ (rtt >> net->sctp.rto_alpha);
} else {
--
1.7.7.6
^ permalink raw reply related
* Re: [PATCH v2 3/3] pppoatm: protect against freeing of vcc
From: chas williams - CONTRACTOR @ 2012-11-28 15:18 UTC (permalink / raw)
To: David Woodhouse
Cc: Krzysztof Mazur, David Laight, davem, netdev, linux-kernel,
nathan
In-Reply-To: <1354098268.21562.44.camel@shinybook.infradead.org>
On Wed, 28 Nov 2012 10:24:28 +0000
David Woodhouse <dwmw2@infradead.org> wrote:
> On Wed, 2012-11-28 at 11:04 +0100, Krzysztof Mazur wrote:
> >
> > The ->close() routine can just abort any pending rx/tx and just wait
> > for completion of currently running rx/tx code. That shouldn't take
> > long.
>
> If it's been submitted to the hardware for DMA, it can't do that very
> easily.
>
> And if I can't be bothered to write code to go through the entire damn
> queue and inspect every packet to see if it's a data packet and check
> the VCI/VPI and try to steal it, it can't be done for the software queue
> either :)
>
> The queue ought to be short; if it isn't, then we already screwed up.
> The close therefore should be quick, and it *doesn't* have to be
> instant.
>
> If someone wants to return immediately, there's always
> vcc_release_async()...
>
i dont think that would be quite the right way to do it.
vcc_release_async() just mark's the vcc for deletion--you still need to
go through and close it eventually. however, nothing would prevent you
from writing a close routine that could just reschedule something
periodically to check to see if the hardware finally finished closing
the vcc and can be reused. the part that needs fixed for this would be
marking the vcc for reuse. you would need to keep the vpi.vci marked
as busy so that someone else doesnt try to reuse it while it is
closing. right now, vcc_destroy_socket() always removes the vcc from
the vcc list -- regardless of whether or not close fully succeeded.
^ permalink raw reply
* Re: "tuntap: multiqueue support" causes udev fork bombs
From: David Miller @ 2012-11-28 15:25 UTC (permalink / raw)
To: rmilasan; +Cc: jslaby, jasowang, netdev, linux-kernel, jirislaby, maxk
In-Reply-To: <20121128113043.39a56f22@coolcat.suse.cz>
Please DO NOT quote a huge email, just to give a small reply to the
discussion. It is never appropriate.
Doing so wastes bandwidth for every single person on the list.
Just quote enough context, and in the case you really could have
quoted nothing at all and everyone would have understood you.
Thanks.
^ permalink raw reply
* Re: Move an interface to init_ne
From: David Shwatrz @ 2012-11-28 15:31 UTC (permalink / raw)
To: Renato Westphal; +Cc: netdev, Eric W. Biederman
In-Reply-To: <CAChaegnKhq50mS+T7XrP9A1hYZbT7c+WGD=tUpWtUY2c-ngb7w@mail.gmail.com>
Renato,
Thanks a lot!
I have an additional question if I may on network namespaces.
I have a machine with two different nics, with two different drivers,
r8169 and 8139too (both RealTek nics).
I have eth0 on the initial network namespace and
no interface on namespace1. (8139too module is not loaded).
But when I run "modprobe 8139too" on namespace1, a device named "eth1"
is created on the initial network namespace and not on namesapce1.
I expected that in such a case, a device named "eth0" will be created
on namespace1, since it was called from namespace1. Or maybe modprobe
does
not consider the namespace from which it was called ?
regards,
DS
On Wed, Nov 28, 2012 at 5:01 PM, Renato Westphal
<renatowestphal@gmail.com> wrote:
> initial network namespace
^ permalink raw reply
* Re: [linux-next-20121127 pcnet32] warning at check_unmap()
From: Denis Kirjanov @ 2012-11-28 15:31 UTC (permalink / raw)
To: Tetsuo Handa; +Cc: pcnet32, netdev
In-Reply-To: <201211282325.BHI28612.SHJtOLOMOFFFVQ@I-love.SAKURA.ne.jp>
You have to convert the driver to generic DMA API
On 11/28/12, Tetsuo Handa <penguin-kernel@i-love.sakura.ne.jp> wrote:
> dma_mapping_error() check seems to be missing at
>
> static netdev_tx_t pcnet32_start_xmit(struct sk_buff *skb,
> struct net_device *dev)
> {
> (...snipped...)
> lp->tx_skbuff[entry] = skb;
> lp->tx_dma_addr[entry] =
> pci_map_single(lp->pci_dev, skb->data, skb->len, PCI_DMA_TODEVICE);
> // this line
> lp->tx_ring[entry].base = cpu_to_le32(lp->tx_dma_addr[entry]);
> wmb(); /* Make sure owner changes after all others are
> visible */
> lp->tx_ring[entry].status = cpu_to_le16(status);
> (...snipped...)
> }
>
> but I don't know how to fix.
>
> [ 20.908272] NET: Registered protocol family 10
> [ 21.627711] pcnet32 0000:02:01.0 eth0: link up
> [ 22.573436] ------------[ cut here ]------------
> [ 22.574952] WARNING: at lib/dma-debug.c:933 check_unmap+0x4a6/0x920()
> [ 22.575669] Hardware name: VMware Virtual Platform
> [ 22.575669] pcnet32 0000:02:01.0: DMA-API: device driver failed to check
> map error[device address=0x000000001a3607f2] [size=90 bytes] [mapped as
> single]
> [ 22.575669] Modules linked in: ipv6 binfmt_misc
> [ 22.575669] Pid: 0, comm: swapper/1 Not tainted 3.7.0-rc7-next-20121127
> #91
> [ 22.575669] Call Trace:
> [ 22.575669] [<c103370d>] warn_slowpath_common+0x6d/0xa0
> [ 22.575669] [<c1249b46>] ? check_unmap+0x4a6/0x920
> [ 22.575669] [<c1249b46>] ? check_unmap+0x4a6/0x920
> [ 22.575669] [<c10337be>] warn_slowpath_fmt+0x2e/0x30
> [ 22.575669] [<c1249b46>] check_unmap+0x4a6/0x920
> [ 22.575669] [<c124a1bb>] debug_dma_unmap_page+0x5b/0x80
> [ 22.575669] [<c13199be>] pcnet32_poll+0x45e/0x850
> [ 22.575669] [<c105dc30>] ? __wake_up+0x40/0x50
> [ 22.575669] [<c138dc70>] net_rx_action+0x90/0x140
> [ 22.575669] [<c103b6f8>] __do_softirq+0x98/0x160
> [ 22.575669] [<c103b660>] ? irq_enter+0x60/0x60
> [ 22.575669] <IRQ> [<c103b52d>] ? irq_exit+0x7d/0x80
> [ 22.575669] [<c1023cb4>] ? smp_apic_timer_interrupt+0x54/0x90
> [ 22.575669] [<c1230fb4>] ? trace_hardirqs_off_thunk+0xc/0x18
> [ 22.575669] [<c144c47e>] ? apic_timer_interrupt+0x32/0x38
> [ 22.575669] [<c100a071>] ? default_idle+0x21/0x40
> [ 22.575669] [<c100a729>] ? cpu_idle+0x69/0xc0
> [ 22.575669] [<c1444e7e>] ? start_secondary+0x1b5/0x1bc
> [ 22.575669] ---[ end trace d906affb5c70936d ]---
> [ 22.575669] Mapped at:
> [ 22.575669] [<c124a4c8>] debug_dma_map_page+0x68/0x140
> [ 22.575669] [<c131acbb>] pcnet32_start_xmit+0x12b/0x220
> [ 22.575669] [<c138bea6>] dev_hard_start_xmit+0x1d6/0x3d0
> [ 22.575669] [<c13a3bc9>] sch_direct_xmit+0x99/0x240
> [ 22.575669] [<c138e003>] dev_queue_xmit+0x143/0x5f0
> --
> 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: [patch] atm: forever loop loading ambassador firmware
From: chas williams - CONTRACTOR @ 2012-11-28 15:40 UTC (permalink / raw)
To: Dan Carpenter; +Cc: David Woodhouse, linux-atm-general, netdev, kernel-janitors
In-Reply-To: <20121127172935.GB1059@elgon.mountain>
On Tue, 27 Nov 2012 20:29:35 +0300
Dan Carpenter <dan.carpenter@oracle.com> wrote:
> There was a forever loop introduced here when we converted this to
> request_firmware() back in 2008.
>
> Signed-off-by: Dan Carpenter <dan.carpenter@oracle.com>
This certainly does seem to be the case.
Acked-by: Chas Williams <chas@cmf.nrl.navy.mil>
> ---
> Spotted in code reading. Untested.
>
> diff --git a/drivers/atm/ambassador.c b/drivers/atm/ambassador.c
> index 89b30f3..ff7bb8a 100644
> --- a/drivers/atm/ambassador.c
> +++ b/drivers/atm/ambassador.c
> @@ -1961,6 +1961,7 @@ static int __devinit ucode_init (loader_block * lb, amb_dev * dev) {
> res = loader_verify(lb, dev, rec);
> if (res)
> break;
> + rec = ihex_next_binrec(rec);
> }
> release_firmware(fw);
> if (!res)
> --
> 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: TCP and reordering
From: David Woodhouse @ 2012-11-28 15:47 UTC (permalink / raw)
To: Eric Dumazet; +Cc: Vijay Subramanian, David Miller, saku, rick.jones2, netdev
In-Reply-To: <1354107140.14302.140.camel@edumazet-glaptop>
[-- Attachment #1: Type: text/plain, Size: 1452 bytes --]
On Wed, 2012-11-28 at 04:52 -0800, Eric Dumazet wrote:
> BQL is nice for high speed adapters.
For adapters with hugely deep queues, surely? There's a massive
correlation between the two, of course — but PPP over L2TP or PPPoE
ought to be included in the classification, right?
> For slow one, you always can stop the queue for each packet given to
> start_xmit()
>
> And restart the queue at TX completion.
Well yes, but only if we get notified of TX completion.
It's simple enough for the tty-based channels, and we can do it with a
vcc->pop() function for PPPoATM. But for PPPoE and L2TP, how do we do
it? We can install a skb destructor... but then we're stomping on TSQ's
use of the destructor by orphaning it too soon.
I'm pondering something along the lines of
if (skb->destructor) {
newskb = skb_clone(skb, GFP_KERNEL);
if (newskb) {
skb_shinfo(newskb) = skb;
skb = newskb;
}
}
skb_orphan(skb);
skb->destructor = ppp_chan_tx_completed;
... and then ppp_chan_tx_completed can also destroy the original skb
(and hence invoke TSQ's destructor too) when the time comes. And in the
(common?) case where we don't have an existing destructor, we don't
bother with the skb_clone.
But I wish there was a nicer way to chain destructors. And no, I don't
count what GSO does. We can't use the cb here anyway since we're passing
it down the stack.
--
dwmw2
[-- Attachment #2: smime.p7s --]
[-- Type: application/x-pkcs7-signature, Size: 6171 bytes --]
^ permalink raw reply
* RE: [E1000-devel] 82571EB: Detected Hardware Unit Hang
From: Fujinaka, Todd @ 2012-11-28 15:53 UTC (permalink / raw)
To: Joe Jin, Ben Hutchings
Cc: Mary Mcgrath, netdev@vger.kernel.org, e1000-devel@lists.sf.net,
linux-kernel@vger.kernel.org, linux-pci
In-Reply-To: <50B5CBD2.5020804@oracle.com>
The only EEPROM I know about or can speak to is the one attached to the 82571 and it doesn't set the MaxPayloadSize. That's done by the BIOS.
Todd Fujinaka
Technical Marketing Engineer
LAN Access Division (LAD)
Intel Corporation
todd.fujinaka@intel.com
(503) 712-4565
-----Original Message-----
From: Joe Jin [mailto:joe.jin@oracle.com]
Sent: Wednesday, November 28, 2012 12:31 AM
To: Ben Hutchings
Cc: Fujinaka, Todd; Mary Mcgrath; netdev@vger.kernel.org; e1000-devel@lists.sf.net; linux-kernel@vger.kernel.org; linux-pci
Subject: Re: [E1000-devel] 82571EB: Detected Hardware Unit Hang
On 11/28/12 02:10, Ben Hutchings wrote:
> On Tue, 2012-11-27 at 17:32 +0000, Fujinaka, Todd wrote:
>> Forgive me if I'm being too repetitious as I think some of this has
>> been mentioned in the past.
>>
>> We (and by we I mean the Ethernet part and driver) can only change
>> the advertised availability of a larger MaxPayloadSize. The size is
>> negotiated by both sides of the link when the link is established.
>> The driver should not change the size of the link as it would be
>> poking at registers outside of its scope and is controlled by the
>> upstream bridge (not us).
> [...]
>
> MaxPayloadSize (MPS) is not negotiated between devices but is
> programmed by the system firmware (at least for devices present at
> boot - the kernel may be responsible in case of hotplug). You can use
> the kernel parameter 'pci=pcie_bus_perf' (or one of several others) to
> set a policy that overrides this, but no policy will allow setting MPS
> above the device's MaxPayloadSizeSupported (MPSS).
>
Ben,
Unfortunately I'm using 3.0.x kernel and this is not included in the kernel.
So I'm trying to use ethtool modify it from eeprom to see if help or no.
Todd, I'll review all MaxPayload for all devices, but need to say if it mismatch, customer could not modify it from BIOS for there was not entry at there, to test it, we have to find how to verify if this is the root cause, so still need to find the offset in eeprom.
Thanks in advance,
Joe
^ permalink raw reply
page: next (older) | prev (newer) | latest
- recent:[subjects (threaded)|topics (new)|topics (active)]
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox