aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/qlcnic/qlcnic_main.c
diff options
context:
space:
mode:
authorAmit Kumar Salecha <amit.salecha@qlogic.com>2010-08-31 13:17:51 -0400
committerDavid S. Miller <davem@davemloft.net>2010-09-01 13:41:57 -0400
commitb5e5492c0d49e2fd6f51961d03b8533435e5e7f5 (patch)
tree6020e160e5b9b84b5d6d94c68f77fb8482d63c71 /drivers/net/qlcnic/qlcnic_main.c
parent7373373d100e5aebe751af0b2609a9a01dad5ac1 (diff)
qlcnic: support mac learning
Device eswitch need to configure with VM's mac address. Hypervisor doesn't provide any utility/callbacks to get VM's mac address. Unicast mac address filter improves performance and also provide packet loopback capability i.e communication between VM. Above features is by default off, can be turned on with module parameter 'mac_learn'. Signed-off-by: Amit Kumar Salecha <amit.salecha@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net/qlcnic/qlcnic_main.c')
-rw-r--r--drivers/net/qlcnic/qlcnic_main.c123
1 files changed, 123 insertions, 0 deletions
diff --git a/drivers/net/qlcnic/qlcnic_main.c b/drivers/net/qlcnic/qlcnic_main.c
index 130f4dbe2f4b..0fbfb53f2594 100644
--- a/drivers/net/qlcnic/qlcnic_main.c
+++ b/drivers/net/qlcnic/qlcnic_main.c
@@ -50,6 +50,10 @@ static int port_mode = QLCNIC_PORT_MODE_AUTO_NEG;
50/* Default to restricted 1G auto-neg mode */ 50/* Default to restricted 1G auto-neg mode */
51static int wol_port_mode = 5; 51static int wol_port_mode = 5;
52 52
53static int qlcnic_mac_learn;
54module_param(qlcnic_mac_learn, int, 0644);
55MODULE_PARM_DESC(qlcnic_mac_learn, "Mac Filter (0=disabled, 1=enabled)");
56
53static int use_msi = 1; 57static int use_msi = 1;
54module_param(use_msi, int, 0644); 58module_param(use_msi, int, 0644);
55MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled"); 59MODULE_PARM_DESC(use_msi, "MSI interrupt (0=disabled, 1=enabled");
@@ -106,6 +110,8 @@ static struct net_device_stats *qlcnic_get_stats(struct net_device *netdev);
106static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long); 110static void qlcnic_config_indev_addr(struct net_device *dev, unsigned long);
107static int qlcnic_start_firmware(struct qlcnic_adapter *); 111static int qlcnic_start_firmware(struct qlcnic_adapter *);
108 112
113static void qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter);
114static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter);
109static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *); 115static void qlcnic_dev_set_npar_ready(struct qlcnic_adapter *);
110static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32); 116static int qlcnicvf_config_led(struct qlcnic_adapter *, u32, u32);
111static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32); 117static int qlcnicvf_config_bridged_mode(struct qlcnic_adapter *, u32);
@@ -1201,6 +1207,9 @@ __qlcnic_down(struct qlcnic_adapter *adapter, struct net_device *netdev)
1201 1207
1202 qlcnic_free_mac_list(adapter); 1208 qlcnic_free_mac_list(adapter);
1203 1209
1210 if (adapter->fhash.fnum)
1211 qlcnic_delete_lb_filters(adapter);
1212
1204 qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE); 1213 qlcnic_nic_set_promisc(adapter, QLCNIC_NIU_NON_PROMISC_MODE);
1205 1214
1206 qlcnic_napi_disable(adapter); 1215 qlcnic_napi_disable(adapter);
@@ -1596,6 +1605,7 @@ qlcnic_probe(struct pci_dev *pdev, const struct pci_device_id *ent)
1596 break; 1605 break;
1597 } 1606 }
1598 1607
1608 qlcnic_alloc_lb_filters_mem(adapter);
1599 qlcnic_create_diag_entries(adapter); 1609 qlcnic_create_diag_entries(adapter);
1600 1610
1601 return 0; 1611 return 0;
@@ -1647,6 +1657,8 @@ static void __devexit qlcnic_remove(struct pci_dev *pdev)
1647 1657
1648 clear_bit(__QLCNIC_RESETTING, &adapter->state); 1658 clear_bit(__QLCNIC_RESETTING, &adapter->state);
1649 1659
1660 qlcnic_free_lb_filters_mem(adapter);
1661
1650 qlcnic_teardown_intr(adapter); 1662 qlcnic_teardown_intr(adapter);
1651 1663
1652 qlcnic_remove_diag_entries(adapter); 1664 qlcnic_remove_diag_entries(adapter);
@@ -1782,6 +1794,111 @@ static int qlcnic_close(struct net_device *netdev)
1782} 1794}
1783 1795
1784static void 1796static void
1797qlcnic_alloc_lb_filters_mem(struct qlcnic_adapter *adapter)
1798{
1799 void *head;
1800 int i;
1801
1802 if (!qlcnic_mac_learn)
1803 return;
1804
1805 spin_lock_init(&adapter->mac_learn_lock);
1806
1807 head = kcalloc(QLCNIC_LB_MAX_FILTERS, sizeof(struct hlist_head),
1808 GFP_KERNEL);
1809 if (!head)
1810 return;
1811
1812 adapter->fhash.fmax = QLCNIC_LB_MAX_FILTERS;
1813 adapter->fhash.fhead = (struct hlist_head *)head;
1814
1815 for (i = 0; i < adapter->fhash.fmax; i++)
1816 INIT_HLIST_HEAD(&adapter->fhash.fhead[i]);
1817}
1818
1819static void qlcnic_free_lb_filters_mem(struct qlcnic_adapter *adapter)
1820{
1821 if (adapter->fhash.fmax && adapter->fhash.fhead)
1822 kfree(adapter->fhash.fhead);
1823
1824 adapter->fhash.fhead = NULL;
1825 adapter->fhash.fmax = 0;
1826}
1827
1828static void qlcnic_change_filter(struct qlcnic_adapter *adapter,
1829 u64 uaddr, struct qlcnic_host_tx_ring *tx_ring)
1830{
1831 struct cmd_desc_type0 *hwdesc;
1832 struct qlcnic_nic_req *req;
1833 struct qlcnic_mac_req *mac_req;
1834 u32 producer;
1835 u64 word;
1836
1837 producer = tx_ring->producer;
1838 hwdesc = &tx_ring->desc_head[tx_ring->producer];
1839
1840 req = (struct qlcnic_nic_req *)hwdesc;
1841 memset(req, 0, sizeof(struct qlcnic_nic_req));
1842 req->qhdr = cpu_to_le64(QLCNIC_REQUEST << 23);
1843
1844 word = QLCNIC_MAC_EVENT | ((u64)(adapter->portnum) << 16);
1845 req->req_hdr = cpu_to_le64(word);
1846
1847 mac_req = (struct qlcnic_mac_req *)&(req->words[0]);
1848 mac_req->op = QLCNIC_MAC_ADD;
1849 memcpy(mac_req->mac_addr, &uaddr, ETH_ALEN);
1850
1851 tx_ring->producer = get_next_index(producer, tx_ring->num_desc);
1852}
1853
1854#define QLCNIC_MAC_HASH(MAC)\
1855 ((((MAC) & 0x70000) >> 0x10) | (((MAC) & 0x70000000000ULL) >> 0x25))
1856
1857static void
1858qlcnic_send_filter(struct qlcnic_adapter *adapter,
1859 struct qlcnic_host_tx_ring *tx_ring,
1860 struct cmd_desc_type0 *first_desc,
1861 struct sk_buff *skb)
1862{
1863 struct ethhdr *phdr = (struct ethhdr *)(skb->data);
1864 struct qlcnic_filter *fil, *tmp_fil;
1865 struct hlist_node *tmp_hnode, *n;
1866 struct hlist_head *head;
1867 u64 src_addr = 0;
1868 u8 hindex;
1869
1870 if (!compare_ether_addr(phdr->h_source, adapter->mac_addr))
1871 return;
1872
1873 if (adapter->fhash.fnum >= adapter->fhash.fmax)
1874 return;
1875
1876 memcpy(&src_addr, phdr->h_source, ETH_ALEN);
1877 hindex = QLCNIC_MAC_HASH(src_addr) & (QLCNIC_LB_MAX_FILTERS - 1);
1878 head = &(adapter->fhash.fhead[hindex]);
1879
1880 hlist_for_each_entry_safe(tmp_fil, tmp_hnode, n, head, fnode) {
1881 if (!memcmp(tmp_fil->faddr, &src_addr, ETH_ALEN)) {
1882 tmp_fil->ftime = jiffies;
1883 return;
1884 }
1885 }
1886
1887 fil = kzalloc(sizeof(struct qlcnic_filter), GFP_ATOMIC);
1888 if (!fil)
1889 return;
1890
1891 qlcnic_change_filter(adapter, src_addr, tx_ring);
1892
1893 fil->ftime = jiffies;
1894 memcpy(fil->faddr, &src_addr, ETH_ALEN);
1895 spin_lock(&adapter->mac_learn_lock);
1896 hlist_add_head(&(fil->fnode), head);
1897 adapter->fhash.fnum++;
1898 spin_unlock(&adapter->mac_learn_lock);
1899}
1900
1901static void
1785qlcnic_tso_check(struct net_device *netdev, 1902qlcnic_tso_check(struct net_device *netdev,
1786 struct qlcnic_host_tx_ring *tx_ring, 1903 struct qlcnic_host_tx_ring *tx_ring,
1787 struct cmd_desc_type0 *first_desc, 1904 struct cmd_desc_type0 *first_desc,
@@ -2090,6 +2207,9 @@ qlcnic_xmit_frame(struct sk_buff *skb, struct net_device *netdev)
2090 2207
2091 qlcnic_tso_check(netdev, tx_ring, first_desc, skb); 2208 qlcnic_tso_check(netdev, tx_ring, first_desc, skb);
2092 2209
2210 if (qlcnic_mac_learn)
2211 qlcnic_send_filter(adapter, tx_ring, first_desc, skb);
2212
2093 qlcnic_update_cmd_producer(adapter, tx_ring); 2213 qlcnic_update_cmd_producer(adapter, tx_ring);
2094 2214
2095 adapter->stats.txbytes += skb->len; 2215 adapter->stats.txbytes += skb->len;
@@ -2900,6 +3020,9 @@ qlcnic_fw_poll_work(struct work_struct *work)
2900 if (qlcnic_check_health(adapter)) 3020 if (qlcnic_check_health(adapter))
2901 return; 3021 return;
2902 3022
3023 if (adapter->fhash.fnum)
3024 qlcnic_prune_lb_filters(adapter);
3025
2903reschedule: 3026reschedule:
2904 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY); 3027 qlcnic_schedule_work(adapter, qlcnic_fw_poll_work, FW_POLL_DELAY);
2905} 3028}