qede: classification configuration
Add the ability to configure basic classification in driver by implementing ndo_set_mac_address() and ndo_set_rx_mode(). Signed-off-by: Sudarsana Kalluru <Sudarsana.Kalluru@qlogic.com> Signed-off-by: Yuval Mintz <Yuval.Mintz@qlogic.com> Signed-off-by: Ariel Elior <Ariel.Elior@qlogic.com> Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Родитель
2950219d87
Коммит
0d8e0aa057
|
@ -87,6 +87,9 @@ struct qede_dev {
|
||||||
struct qed_update_vport_rss_params rss_params;
|
struct qed_update_vport_rss_params rss_params;
|
||||||
u16 q_num_rx_buffers; /* Must be a power of two */
|
u16 q_num_rx_buffers; /* Must be a power of two */
|
||||||
u16 q_num_tx_buffers; /* Must be a power of two */
|
u16 q_num_tx_buffers; /* Must be a power of two */
|
||||||
|
|
||||||
|
struct delayed_work sp_task;
|
||||||
|
unsigned long sp_flags;
|
||||||
};
|
};
|
||||||
|
|
||||||
enum QEDE_STATE {
|
enum QEDE_STATE {
|
||||||
|
@ -184,6 +187,13 @@ struct qede_fastpath {
|
||||||
|
|
||||||
#define QEDE_CSUM_ERROR BIT(0)
|
#define QEDE_CSUM_ERROR BIT(0)
|
||||||
#define QEDE_CSUM_UNNECESSARY BIT(1)
|
#define QEDE_CSUM_UNNECESSARY BIT(1)
|
||||||
|
|
||||||
|
#define QEDE_SP_RX_MODE 1
|
||||||
|
|
||||||
|
union qede_reload_args {
|
||||||
|
u16 mtu;
|
||||||
|
};
|
||||||
|
|
||||||
#define RX_RING_SIZE_POW 13
|
#define RX_RING_SIZE_POW 13
|
||||||
#define RX_RING_SIZE BIT(RX_RING_SIZE_POW)
|
#define RX_RING_SIZE BIT(RX_RING_SIZE_POW)
|
||||||
#define NUM_RX_BDS_MAX (RX_RING_SIZE - 1)
|
#define NUM_RX_BDS_MAX (RX_RING_SIZE - 1)
|
||||||
|
|
|
@ -1030,10 +1030,31 @@ static irqreturn_t qede_msix_fp_int(int irq, void *fp_cookie)
|
||||||
|
|
||||||
static int qede_open(struct net_device *ndev);
|
static int qede_open(struct net_device *ndev);
|
||||||
static int qede_close(struct net_device *ndev);
|
static int qede_close(struct net_device *ndev);
|
||||||
|
static int qede_set_mac_addr(struct net_device *ndev, void *p);
|
||||||
|
static void qede_set_rx_mode(struct net_device *ndev);
|
||||||
|
static void qede_config_rx_mode(struct net_device *ndev);
|
||||||
|
|
||||||
|
static int qede_set_ucast_rx_mac(struct qede_dev *edev,
|
||||||
|
enum qed_filter_xcast_params_type opcode,
|
||||||
|
unsigned char mac[ETH_ALEN])
|
||||||
|
{
|
||||||
|
struct qed_filter_params filter_cmd;
|
||||||
|
|
||||||
|
memset(&filter_cmd, 0, sizeof(filter_cmd));
|
||||||
|
filter_cmd.type = QED_FILTER_TYPE_UCAST;
|
||||||
|
filter_cmd.filter.ucast.type = opcode;
|
||||||
|
filter_cmd.filter.ucast.mac_valid = 1;
|
||||||
|
ether_addr_copy(filter_cmd.filter.ucast.mac, mac);
|
||||||
|
|
||||||
|
return edev->ops->filter_config(edev->cdev, &filter_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
static const struct net_device_ops qede_netdev_ops = {
|
static const struct net_device_ops qede_netdev_ops = {
|
||||||
.ndo_open = qede_open,
|
.ndo_open = qede_open,
|
||||||
.ndo_stop = qede_close,
|
.ndo_stop = qede_close,
|
||||||
.ndo_start_xmit = qede_start_xmit,
|
.ndo_start_xmit = qede_start_xmit,
|
||||||
|
.ndo_set_rx_mode = qede_set_rx_mode,
|
||||||
|
.ndo_set_mac_address = qede_set_mac_addr,
|
||||||
.ndo_validate_addr = eth_validate_addr,
|
.ndo_validate_addr = eth_validate_addr,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
@ -1198,6 +1219,20 @@ err:
|
||||||
return -ENOMEM;
|
return -ENOMEM;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static void qede_sp_task(struct work_struct *work)
|
||||||
|
{
|
||||||
|
struct qede_dev *edev = container_of(work, struct qede_dev,
|
||||||
|
sp_task.work);
|
||||||
|
mutex_lock(&edev->qede_lock);
|
||||||
|
|
||||||
|
if (edev->state == QEDE_STATE_OPEN) {
|
||||||
|
if (test_and_clear_bit(QEDE_SP_RX_MODE, &edev->sp_flags))
|
||||||
|
qede_config_rx_mode(edev->ndev);
|
||||||
|
}
|
||||||
|
|
||||||
|
mutex_unlock(&edev->qede_lock);
|
||||||
|
}
|
||||||
|
|
||||||
static void qede_update_pf_params(struct qed_dev *cdev)
|
static void qede_update_pf_params(struct qed_dev *cdev)
|
||||||
{
|
{
|
||||||
struct qed_pf_params pf_params;
|
struct qed_pf_params pf_params;
|
||||||
|
@ -1269,6 +1304,9 @@ static int __qede_probe(struct pci_dev *pdev, u32 dp_module, u8 dp_level,
|
||||||
|
|
||||||
edev->ops->common->set_id(cdev, edev->ndev->name, DRV_MODULE_VERSION);
|
edev->ops->common->set_id(cdev, edev->ndev->name, DRV_MODULE_VERSION);
|
||||||
|
|
||||||
|
INIT_DELAYED_WORK(&edev->sp_task, qede_sp_task);
|
||||||
|
mutex_init(&edev->qede_lock);
|
||||||
|
|
||||||
DP_INFO(edev, "Ending successfully qede probe\n");
|
DP_INFO(edev, "Ending successfully qede probe\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -1306,6 +1344,7 @@ static void __qede_remove(struct pci_dev *pdev, enum qede_remove_mode mode)
|
||||||
|
|
||||||
DP_INFO(edev, "Starting qede_remove\n");
|
DP_INFO(edev, "Starting qede_remove\n");
|
||||||
|
|
||||||
|
cancel_delayed_work_sync(&edev->sp_task);
|
||||||
unregister_netdev(ndev);
|
unregister_netdev(ndev);
|
||||||
|
|
||||||
edev->ops->common->set_power_state(cdev, PCI_D0);
|
edev->ops->common->set_power_state(cdev, PCI_D0);
|
||||||
|
@ -2036,6 +2075,24 @@ static int qede_start_queues(struct qede_dev *edev)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qede_set_mcast_rx_mac(struct qede_dev *edev,
|
||||||
|
enum qed_filter_xcast_params_type opcode,
|
||||||
|
unsigned char *mac, int num_macs)
|
||||||
|
{
|
||||||
|
struct qed_filter_params filter_cmd;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
memset(&filter_cmd, 0, sizeof(filter_cmd));
|
||||||
|
filter_cmd.type = QED_FILTER_TYPE_MCAST;
|
||||||
|
filter_cmd.filter.mcast.type = opcode;
|
||||||
|
filter_cmd.filter.mcast.num = num_macs;
|
||||||
|
|
||||||
|
for (i = 0; i < num_macs; i++, mac += ETH_ALEN)
|
||||||
|
ether_addr_copy(filter_cmd.filter.mcast.mac[i], mac);
|
||||||
|
|
||||||
|
return edev->ops->filter_config(edev->cdev, &filter_cmd);
|
||||||
|
}
|
||||||
|
|
||||||
enum qede_unload_mode {
|
enum qede_unload_mode {
|
||||||
QEDE_UNLOAD_NORMAL,
|
QEDE_UNLOAD_NORMAL,
|
||||||
};
|
};
|
||||||
|
@ -2046,6 +2103,9 @@ static void qede_unload(struct qede_dev *edev, enum qede_unload_mode mode)
|
||||||
|
|
||||||
DP_INFO(edev, "Starting qede unload\n");
|
DP_INFO(edev, "Starting qede unload\n");
|
||||||
|
|
||||||
|
mutex_lock(&edev->qede_lock);
|
||||||
|
edev->state = QEDE_STATE_CLOSED;
|
||||||
|
|
||||||
/* Close OS Tx */
|
/* Close OS Tx */
|
||||||
netif_tx_disable(edev->ndev);
|
netif_tx_disable(edev->ndev);
|
||||||
netif_carrier_off(edev->ndev);
|
netif_carrier_off(edev->ndev);
|
||||||
|
@ -2120,6 +2180,9 @@ static int qede_load(struct qede_dev *edev, enum qede_load_mode mode)
|
||||||
/* Add primary mac and set Rx filters */
|
/* Add primary mac and set Rx filters */
|
||||||
ether_addr_copy(edev->primary_mac, edev->ndev->dev_addr);
|
ether_addr_copy(edev->primary_mac, edev->ndev->dev_addr);
|
||||||
|
|
||||||
|
mutex_lock(&edev->qede_lock);
|
||||||
|
edev->state = QEDE_STATE_OPEN;
|
||||||
|
mutex_unlock(&edev->qede_lock);
|
||||||
DP_INFO(edev, "Ending successfully qede load\n");
|
DP_INFO(edev, "Ending successfully qede load\n");
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
|
@ -2159,3 +2222,181 @@ static int qede_close(struct net_device *ndev)
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int qede_set_mac_addr(struct net_device *ndev, void *p)
|
||||||
|
{
|
||||||
|
struct qede_dev *edev = netdev_priv(ndev);
|
||||||
|
struct sockaddr *addr = p;
|
||||||
|
int rc;
|
||||||
|
|
||||||
|
ASSERT_RTNL(); /* @@@TBD To be removed */
|
||||||
|
|
||||||
|
DP_INFO(edev, "Set_mac_addr called\n");
|
||||||
|
|
||||||
|
if (!is_valid_ether_addr(addr->sa_data)) {
|
||||||
|
DP_NOTICE(edev, "The MAC address is not valid\n");
|
||||||
|
return -EFAULT;
|
||||||
|
}
|
||||||
|
|
||||||
|
ether_addr_copy(ndev->dev_addr, addr->sa_data);
|
||||||
|
|
||||||
|
if (!netif_running(ndev)) {
|
||||||
|
DP_NOTICE(edev, "The device is currently down\n");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Remove the previous primary mac */
|
||||||
|
rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_DEL,
|
||||||
|
edev->primary_mac);
|
||||||
|
if (rc)
|
||||||
|
return rc;
|
||||||
|
|
||||||
|
/* Add MAC filter according to the new unicast HW MAC address */
|
||||||
|
ether_addr_copy(edev->primary_mac, ndev->dev_addr);
|
||||||
|
return qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_ADD,
|
||||||
|
edev->primary_mac);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qede_configure_mcast_filtering(struct net_device *ndev,
|
||||||
|
enum qed_filter_rx_mode_type *accept_flags)
|
||||||
|
{
|
||||||
|
struct qede_dev *edev = netdev_priv(ndev);
|
||||||
|
unsigned char *mc_macs, *temp;
|
||||||
|
struct netdev_hw_addr *ha;
|
||||||
|
int rc = 0, mc_count;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
size = 64 * ETH_ALEN;
|
||||||
|
|
||||||
|
mc_macs = kzalloc(size, GFP_KERNEL);
|
||||||
|
if (!mc_macs) {
|
||||||
|
DP_NOTICE(edev,
|
||||||
|
"Failed to allocate memory for multicast MACs\n");
|
||||||
|
rc = -ENOMEM;
|
||||||
|
goto exit;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = mc_macs;
|
||||||
|
|
||||||
|
/* Remove all previously configured MAC filters */
|
||||||
|
rc = qede_set_mcast_rx_mac(edev, QED_FILTER_XCAST_TYPE_DEL,
|
||||||
|
mc_macs, 1);
|
||||||
|
if (rc)
|
||||||
|
goto exit;
|
||||||
|
|
||||||
|
netif_addr_lock_bh(ndev);
|
||||||
|
|
||||||
|
mc_count = netdev_mc_count(ndev);
|
||||||
|
if (mc_count < 64) {
|
||||||
|
netdev_for_each_mc_addr(ha, ndev) {
|
||||||
|
ether_addr_copy(temp, ha->addr);
|
||||||
|
temp += ETH_ALEN;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
netif_addr_unlock_bh(ndev);
|
||||||
|
|
||||||
|
/* Check for all multicast @@@TBD resource allocation */
|
||||||
|
if ((ndev->flags & IFF_ALLMULTI) ||
|
||||||
|
(mc_count > 64)) {
|
||||||
|
if (*accept_flags == QED_FILTER_RX_MODE_TYPE_REGULAR)
|
||||||
|
*accept_flags = QED_FILTER_RX_MODE_TYPE_MULTI_PROMISC;
|
||||||
|
} else {
|
||||||
|
/* Add all multicast MAC filters */
|
||||||
|
rc = qede_set_mcast_rx_mac(edev, QED_FILTER_XCAST_TYPE_ADD,
|
||||||
|
mc_macs, mc_count);
|
||||||
|
}
|
||||||
|
|
||||||
|
exit:
|
||||||
|
kfree(mc_macs);
|
||||||
|
return rc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void qede_set_rx_mode(struct net_device *ndev)
|
||||||
|
{
|
||||||
|
struct qede_dev *edev = netdev_priv(ndev);
|
||||||
|
|
||||||
|
DP_INFO(edev, "qede_set_rx_mode called\n");
|
||||||
|
|
||||||
|
if (edev->state != QEDE_STATE_OPEN) {
|
||||||
|
DP_INFO(edev,
|
||||||
|
"qede_set_rx_mode called while interface is down\n");
|
||||||
|
} else {
|
||||||
|
set_bit(QEDE_SP_RX_MODE, &edev->sp_flags);
|
||||||
|
schedule_delayed_work(&edev->sp_task, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* Must be called with qede_lock held */
|
||||||
|
static void qede_config_rx_mode(struct net_device *ndev)
|
||||||
|
{
|
||||||
|
enum qed_filter_rx_mode_type accept_flags = QED_FILTER_TYPE_UCAST;
|
||||||
|
struct qede_dev *edev = netdev_priv(ndev);
|
||||||
|
struct qed_filter_params rx_mode;
|
||||||
|
unsigned char *uc_macs, *temp;
|
||||||
|
struct netdev_hw_addr *ha;
|
||||||
|
int rc, uc_count;
|
||||||
|
size_t size;
|
||||||
|
|
||||||
|
netif_addr_lock_bh(ndev);
|
||||||
|
|
||||||
|
uc_count = netdev_uc_count(ndev);
|
||||||
|
size = uc_count * ETH_ALEN;
|
||||||
|
|
||||||
|
uc_macs = kzalloc(size, GFP_ATOMIC);
|
||||||
|
if (!uc_macs) {
|
||||||
|
DP_NOTICE(edev, "Failed to allocate memory for unicast MACs\n");
|
||||||
|
netif_addr_unlock_bh(ndev);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
temp = uc_macs;
|
||||||
|
netdev_for_each_uc_addr(ha, ndev) {
|
||||||
|
ether_addr_copy(temp, ha->addr);
|
||||||
|
temp += ETH_ALEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
netif_addr_unlock_bh(ndev);
|
||||||
|
|
||||||
|
/* Configure the struct for the Rx mode */
|
||||||
|
memset(&rx_mode, 0, sizeof(struct qed_filter_params));
|
||||||
|
rx_mode.type = QED_FILTER_TYPE_RX_MODE;
|
||||||
|
|
||||||
|
/* Remove all previous unicast secondary macs and multicast macs
|
||||||
|
* (configrue / leave the primary mac)
|
||||||
|
*/
|
||||||
|
rc = qede_set_ucast_rx_mac(edev, QED_FILTER_XCAST_TYPE_REPLACE,
|
||||||
|
edev->primary_mac);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
/* Check for promiscuous */
|
||||||
|
if ((ndev->flags & IFF_PROMISC) ||
|
||||||
|
(uc_count > 15)) { /* @@@TBD resource allocation - 1 */
|
||||||
|
accept_flags = QED_FILTER_RX_MODE_TYPE_PROMISC;
|
||||||
|
} else {
|
||||||
|
/* Add MAC filters according to the unicast secondary macs */
|
||||||
|
int i;
|
||||||
|
|
||||||
|
temp = uc_macs;
|
||||||
|
for (i = 0; i < uc_count; i++) {
|
||||||
|
rc = qede_set_ucast_rx_mac(edev,
|
||||||
|
QED_FILTER_XCAST_TYPE_ADD,
|
||||||
|
temp);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
|
||||||
|
temp += ETH_ALEN;
|
||||||
|
}
|
||||||
|
|
||||||
|
rc = qede_configure_mcast_filtering(ndev, &accept_flags);
|
||||||
|
if (rc)
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
rx_mode.filter.accept_flags = accept_flags;
|
||||||
|
edev->ops->filter_config(edev->cdev, &rx_mode);
|
||||||
|
out:
|
||||||
|
kfree(uc_macs);
|
||||||
|
}
|
||||||
|
|
Загрузка…
Ссылка в новой задаче