Skip to content

Commit

Permalink
netxen: enable ip addr hashing
Browse files Browse the repository at this point in the history
NX3031 hardware requires local IP addresses for packet
accumulation (LRO). IP address hashing is required to
distinguish a local TCP flow from others (forwarded or
guest).

This patch adds listener for IP and netdev events and
configures IP address in the firmware.

Signed-off-by: Amit Kumar Salecha <amit@netxen.com>
Signed-off-by: Dhananjay Phadke <dhananjay@netxen.com>
Signed-off-by: David S. Miller <davem@davemloft.net>
  • Loading branch information
Dhananjay Phadke authored and David S. Miller committed Jul 27, 2009
1 parent 68b3cae commit 6598b16
Show file tree
Hide file tree
Showing 4 changed files with 182 additions and 25 deletions.
5 changes: 5 additions & 0 deletions drivers/net/netxen/netxen_nic.h
Original file line number Diff line number Diff line change
Expand Up @@ -380,6 +380,7 @@ struct rcv_desc {
};

/* opcode field in status_desc */
#define NETXEN_NIC_SYN_OFFLOAD 0x03
#define NETXEN_NIC_RXPKT_DESC 0x04
#define NETXEN_OLD_RXPKT_DESC 0x3f
#define NETXEN_NIC_RESPONSE_DESC 0x05
Expand Down Expand Up @@ -1078,6 +1079,9 @@ typedef struct {

#define NX_MAC_EVENT 0x1

#define NX_IP_UP 2
#define NX_IP_DOWN 3

/*
* Driver --> Firmware
*/
Expand Down Expand Up @@ -1443,6 +1447,7 @@ void netxen_p3_free_mac_list(struct netxen_adapter *adapter);
int netxen_p3_nic_set_promisc(struct netxen_adapter *adapter, u32);
int netxen_config_intr_coalesce(struct netxen_adapter *adapter);
int netxen_config_rss(struct netxen_adapter *adapter, int enable);
int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd);
int netxen_linkevent_request(struct netxen_adapter *adapter, int enable);
void netxen_advert_link_change(struct netxen_adapter *adapter, int linkup);

Expand Down
24 changes: 24 additions & 0 deletions drivers/net/netxen/netxen_nic_hw.c
Original file line number Diff line number Diff line change
Expand Up @@ -706,6 +706,30 @@ int netxen_config_rss(struct netxen_adapter *adapter, int enable)
return rv;
}

int netxen_config_ipaddr(struct netxen_adapter *adapter, u32 ip, int cmd)
{
nx_nic_req_t req;
u64 word;
int rv;

memset(&req, 0, sizeof(nx_nic_req_t));
req.qhdr = cpu_to_le64(NX_HOST_REQUEST << 23);

word = NX_NIC_H2C_OPCODE_CONFIG_IPADDR | ((u64)adapter->portnum << 16);
req.req_hdr = cpu_to_le64(word);

req.words[0] = cpu_to_le64(cmd);
req.words[1] = cpu_to_le64(ip);

rv = netxen_send_cmd_descs(adapter, (struct cmd_desc_type0 *)&req, 1);
if (rv != 0) {
printk(KERN_ERR "%s: could not notify %s IP 0x%x reuqest\n",
adapter->netdev->name,
(cmd == NX_IP_UP) ? "Add" : "Remove", ip);
}
return rv;
}

int netxen_linkevent_request(struct netxen_adapter *adapter, int enable)
{
nx_nic_req_t req;
Expand Down
52 changes: 27 additions & 25 deletions drivers/net/netxen/netxen_nic_init.c
Original file line number Diff line number Diff line change
Expand Up @@ -880,46 +880,46 @@ netxen_validate_firmware(struct netxen_adapter *adapter, const char *fwname)
return 0;
}

void netxen_request_firmware(struct netxen_adapter *adapter)
static int
netxen_p3_has_mn(struct netxen_adapter *adapter)
{
u32 capability, flashed_ver;
u8 fw_type;
struct pci_dev *pdev = adapter->pdev;
int rc = 0;

if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
fw_type = NX_P2_MN_ROMIMAGE;
goto request_fw;
} else {
fw_type = NX_P3_CT_ROMIMAGE;
goto request_fw;
}

request_mn:
capability = 0;

netxen_rom_fast_read(adapter,
NX_FW_VERSION_OFFSET, (int *)&flashed_ver);
flashed_ver = NETXEN_DECODE_VERSION(flashed_ver);

if (flashed_ver >= NETXEN_VERSION_CODE(4, 0, 220)) {

capability = NXRD32(adapter, NX_PEG_TUNE_CAPABILITY);
if (capability & NX_PEG_TUNE_MN_PRESENT) {
fw_type = NX_P3_MN_ROMIMAGE;
goto request_fw;
}
if (capability & NX_PEG_TUNE_MN_PRESENT)
return 1;
}
return 0;
}

void netxen_request_firmware(struct netxen_adapter *adapter)
{
u8 fw_type;
struct pci_dev *pdev = adapter->pdev;
int rc = 0;

if (NX_IS_REVISION_P2(adapter->ahw.revision_id)) {
fw_type = NX_P2_MN_ROMIMAGE;
goto request_fw;
}

fw_type = NX_FLASH_ROMIMAGE;
adapter->fw = NULL;
goto done;
fw_type = netxen_p3_has_mn(adapter) ?
NX_P3_MN_ROMIMAGE : NX_P3_CT_ROMIMAGE;

request_fw:
rc = request_firmware(&adapter->fw, fw_name[fw_type], &pdev->dev);
if (rc != 0) {
if (fw_type == NX_P3_CT_ROMIMAGE) {
if (fw_type == NX_P3_MN_ROMIMAGE) {
msleep(1);
goto request_mn;
fw_type = NX_P3_CT_ROMIMAGE;
goto request_fw;
}

fw_type = NX_FLASH_ROMIMAGE;
Expand All @@ -931,9 +931,10 @@ void netxen_request_firmware(struct netxen_adapter *adapter)
if (rc != 0) {
release_firmware(adapter->fw);

if (fw_type == NX_P3_CT_ROMIMAGE) {
if (fw_type == NX_P3_MN_ROMIMAGE) {
msleep(1);
goto request_mn;
fw_type = NX_P3_CT_ROMIMAGE;
goto request_fw;
}

fw_type = NX_FLASH_ROMIMAGE;
Expand Down Expand Up @@ -1292,6 +1293,7 @@ netxen_process_rcv_ring(struct nx_host_sds_ring *sds_ring, int max)
switch (opcode) {
case NETXEN_NIC_RXPKT_DESC:
case NETXEN_OLD_RXPKT_DESC:
case NETXEN_NIC_SYN_OFFLOAD:
break;
case NETXEN_NIC_RESPONSE_DESC:
netxen_handle_fw_message(desc_cnt, consumer, sds_ring);
Expand Down
126 changes: 126 additions & 0 deletions drivers/net/netxen/netxen_nic_main.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,6 +39,7 @@
#include <linux/if_vlan.h>
#include <net/ip.h>
#include <linux/ipv6.h>
#include <linux/inetdevice.h>

MODULE_DESCRIPTION("NetXen Multi port (1/10) Gigabit Network Driver");
MODULE_LICENSE("GPL");
Expand Down Expand Up @@ -1780,6 +1781,125 @@ static void netxen_nic_poll_controller(struct net_device *netdev)
}
#endif

#define is_netxen_netdev(dev) (dev->netdev_ops == &netxen_netdev_ops)

static int
netxen_destip_supported(struct netxen_adapter *adapter)
{
if (NX_IS_REVISION_P2(adapter->ahw.revision_id))
return 0;

if (adapter->ahw.cut_through)
return 0;

return 1;
}

static int netxen_netdev_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct netxen_adapter *adapter;
struct net_device *dev = (struct net_device *)ptr;
struct in_device *indev;

recheck:
if (dev == NULL)
goto done;

if (dev->priv_flags & IFF_802_1Q_VLAN) {
dev = vlan_dev_real_dev(dev);
goto recheck;
}

if (!is_netxen_netdev(dev))
goto done;

adapter = netdev_priv(dev);

if (!adapter || !netxen_destip_supported(adapter))
goto done;

if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
goto done;

indev = in_dev_get(dev);
if (!indev)
goto done;

for_ifa(indev) {
switch (event) {
case NETDEV_UP:
netxen_config_ipaddr(adapter,
ifa->ifa_address, NX_IP_UP);
break;
case NETDEV_DOWN:
netxen_config_ipaddr(adapter,
ifa->ifa_address, NX_IP_DOWN);
break;
default:
break;
}
} endfor_ifa(indev);

in_dev_put(indev);
done:
return NOTIFY_DONE;
}

static int
netxen_inetaddr_event(struct notifier_block *this,
unsigned long event, void *ptr)
{
struct netxen_adapter *adapter;
struct net_device *dev;

struct in_ifaddr *ifa = (struct in_ifaddr *)ptr;

dev = ifa->ifa_dev ? ifa->ifa_dev->dev : NULL;

recheck:
if (dev == NULL || !netif_running(dev))
goto done;

if (dev->priv_flags & IFF_802_1Q_VLAN) {
dev = vlan_dev_real_dev(dev);
goto recheck;
}

if (!is_netxen_netdev(dev))
goto done;

adapter = netdev_priv(dev);

if (!adapter || !netxen_destip_supported(adapter))
goto done;

if (adapter->is_up != NETXEN_ADAPTER_UP_MAGIC)
goto done;

switch (event) {
case NETDEV_UP:
netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_UP);
break;
case NETDEV_DOWN:
netxen_config_ipaddr(adapter, ifa->ifa_address, NX_IP_DOWN);
break;
default:
break;
}

done:
return NOTIFY_DONE;
}

static struct notifier_block netxen_netdev_cb = {
.notifier_call = netxen_netdev_event,
};

static struct notifier_block netxen_inetaddr_cb = {
.notifier_call = netxen_inetaddr_event,
};

static struct pci_driver netxen_driver = {
.name = netxen_nic_driver_name,
.id_table = netxen_pci_tbl,
Expand All @@ -1800,6 +1920,9 @@ static int __init netxen_init_module(void)
if ((netxen_workq = create_singlethread_workqueue("netxen")) == NULL)
return -ENOMEM;

register_netdevice_notifier(&netxen_netdev_cb);
register_inetaddr_notifier(&netxen_inetaddr_cb);

return pci_register_driver(&netxen_driver);
}

Expand All @@ -1808,6 +1931,9 @@ module_init(netxen_init_module);
static void __exit netxen_exit_module(void)
{
pci_unregister_driver(&netxen_driver);

unregister_inetaddr_notifier(&netxen_inetaddr_cb);
unregister_netdevice_notifier(&netxen_netdev_cb);
destroy_workqueue(netxen_workq);
}

Expand Down

0 comments on commit 6598b16

Please sign in to comment.