summaryrefslogtreecommitdiff
path: root/kmod/igb/igb_main.c
diff options
context:
space:
mode:
Diffstat (limited to 'kmod/igb/igb_main.c')
-rw-r--r--kmod/igb/igb_main.c189
1 files changed, 162 insertions, 27 deletions
diff --git a/kmod/igb/igb_main.c b/kmod/igb/igb_main.c
index c8a4a7e3..1f3ae697 100644
--- a/kmod/igb/igb_main.c
+++ b/kmod/igb/igb_main.c
@@ -96,6 +96,7 @@ static const struct pci_device_id igb_pci_tbl[] = {
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_FIBER) },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES) },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SGMII) },
+ { PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_AUTOMOTIVE) },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_COPPER_FLASHLESS) },
{ PCI_VDEVICE(INTEL, E1000_DEV_ID_I210_SERDES_FLASHLESS) },
/* required last entry */
@@ -121,11 +122,17 @@ static void igb_clean_all_tx_rings(struct igb_adapter *);
static void igb_clean_all_rx_rings(struct igb_adapter *);
static void igb_clean_tx_ring(struct igb_ring *);
static void igb_set_rx_mode(struct net_device *);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
+static void igb_update_phy_info(struct timer_list *);
+static void igb_watchdog(struct timer_list *);
+static void igb_dma_err_timer(struct timer_list *);
+#else
static void igb_update_phy_info(unsigned long);
static void igb_watchdog(unsigned long);
+static void igb_dma_err_timer(unsigned long data);
+#endif
static void igb_watchdog_task(struct work_struct *);
static void igb_dma_err_task(struct work_struct *);
-static void igb_dma_err_timer(unsigned long data);
/* AVB specific */
#ifdef HAVE_NDO_SELECT_QUEUE_ACCEL_FALLBACK
static u16 igb_select_queue(struct net_device *dev, struct sk_buff *skb,
@@ -214,7 +221,11 @@ static long igb_ioctl_file(struct file *file, unsigned int cmd,
unsigned long arg);
static void igb_vm_open(struct vm_area_struct *vma);
static void igb_vm_close(struct vm_area_struct *vma);
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
+static int igb_vm_fault(struct vm_fault *fdata);
+#else
static int igb_vm_fault(struct vm_area_struct *area, struct vm_fault *fdata);
+#endif
static int igb_mmap(struct file *file, struct vm_area_struct *vma);
static ssize_t igb_read(struct file *file, char __user *buf, size_t count,
loff_t *pos);
@@ -458,7 +469,7 @@ static void igb_cache_ring_register(struct igb_adapter *adapter)
u32 e1000_read_reg(struct e1000_hw *hw, u32 reg)
{
struct igb_adapter *igb = container_of(hw, struct igb_adapter, hw);
- u8 __iomem *hw_addr = ACCESS_ONCE(hw->hw_addr);
+ u8 __iomem *hw_addr = READ_ONCE(hw->hw_addr);
u32 value = 0;
if (E1000_REMOVED(hw_addr))
@@ -1090,8 +1101,13 @@ static void igb_set_interrupt_capability(struct igb_adapter *adapter, bool msix)
for (i = 0; i < numvecs; i++)
adapter->msix_entries[i].entry = i;
- err = pci_enable_msix(pdev,
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,12,0)
+ err = pci_enable_msix_exact(pdev,
adapter->msix_entries, numvecs);
+#else
+ err = pci_enable_msix(pdev,
+ adapter->msix_entries, numvecs);
+#endif
if (err == 0)
break;
}
@@ -1810,7 +1826,7 @@ static s32 igb_init_i2c(struct igb_adapter *adapter)
* igb_up - Open the interface and prepare it to handle traffic
* @adapter: board private structure
**/
-int igb_up(struct igb_adapter *adapter)
+void igb_up(struct igb_adapter *adapter)
{
struct e1000_hw *hw = &adapter->hw;
int i;
@@ -1854,7 +1870,6 @@ int igb_up(struct igb_adapter *adapter)
(!hw->dev_spec._82575.eee_disable))
adapter->eee_advert = MDIO_EEE_100TX | MDIO_EEE_1000T;
- return 0;
}
void igb_down(struct igb_adapter *adapter)
@@ -2877,6 +2892,13 @@ static int igb_probe(struct pci_dev *pdev,
/* Check if Media Autosense is enabled */
if (hw->mac.type == e1000_82580)
igb_init_mas(adapter);
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
+ timer_setup(&adapter->watchdog_timer, &igb_watchdog, 0);
+ if (adapter->flags & IGB_FLAG_DETECT_BAD_DMA)
+ timer_setup(&adapter->dma_err_timer, &igb_dma_err_timer, 0);
+ timer_setup(&adapter->phy_info_timer, &igb_update_phy_info, 0);
+#else
setup_timer(&adapter->watchdog_timer, &igb_watchdog,
(unsigned long) adapter);
if (adapter->flags & IGB_FLAG_DETECT_BAD_DMA)
@@ -2884,6 +2906,7 @@ static int igb_probe(struct pci_dev *pdev,
(unsigned long) adapter);
setup_timer(&adapter->phy_info_timer, &igb_update_phy_info,
(unsigned long) adapter);
+#endif
INIT_WORK(&adapter->reset_task, igb_reset_task);
INIT_WORK(&adapter->watchdog_task, igb_watchdog_task);
@@ -4673,9 +4696,19 @@ static void igb_spoof_check(struct igb_adapter *adapter)
/* Need to wait a few seconds after link up to get diagnostic information from
* the phy
*/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
+static void igb_update_phy_info(struct timer_list *timer)
+#else
static void igb_update_phy_info(unsigned long data)
+#endif
{
- struct igb_adapter *adapter = (struct igb_adapter *) data;
+ struct igb_adapter *adapter;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
+ adapter = container_of(timer, struct igb_adapter, watchdog_timer);
+#else
+ adapter = (struct igb_adapter *) data;
+#endif
e1000_get_phy_info(&adapter->hw);
}
@@ -4725,9 +4758,20 @@ bool igb_has_link(struct igb_adapter *adapter)
* igb_watchdog - Timer Call-back
* @data: pointer to adapter cast into an unsigned long
**/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
+static void igb_watchdog(struct timer_list *timer)
+#else
static void igb_watchdog(unsigned long data)
+#endif
{
- struct igb_adapter *adapter = (struct igb_adapter *)data;
+ struct igb_adapter *adapter;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
+ adapter = container_of(timer, struct igb_adapter, watchdog_timer);
+#else
+ adapter = (struct igb_adapter *)data;
+#endif
+
/* Do the rest outside of interrupt context */
schedule_work(&adapter->watchdog_task);
}
@@ -4983,9 +5027,20 @@ dma_timer_reset:
* igb_dma_err_timer - Timer Call-back
* @data: pointer to adapter cast into an unsigned long
**/
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
+static void igb_dma_err_timer(struct timer_list *timer)
+#else
static void igb_dma_err_timer(unsigned long data)
+#endif
{
- struct igb_adapter *adapter = (struct igb_adapter *)data;
+ struct igb_adapter *adapter;
+
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,15,0)
+ adapter = container_of(timer, struct igb_adapter, dma_err_timer);
+#else
+ adapter = (struct igb_adapter *)data;
+#endif
+
/* Do the rest outside of interrupt context */
schedule_work(&adapter->dma_err_task);
}
@@ -9606,10 +9661,7 @@ static void igb_io_resume(struct pci_dev *pdev)
}
if (netif_running(netdev)) {
- if (igb_up(adapter)) {
- dev_err(pci_dev_to_dev(pdev), "igb_up failed after reset\n");
- return;
- }
+ igb_up(adapter);
}
netif_device_attach(netdev);
@@ -10218,7 +10270,14 @@ static int igb_bind(struct file *file, void __user *argp)
if (copy_from_user(&req, argp, sizeof(req)))
return -EFAULT;
+
+ /*
+ * Set the last character of req.iface to '/0' to
+ * guarantee null termination of req.iface string
+ * param in printk call.
+ */
+ req.iface[IGB_BIND_NAMESZ-1] = 0;
printk("bind to iface %s\n", req.iface);
if (igb_priv == NULL) {
@@ -10309,11 +10368,16 @@ static long igb_mapbuf_user(struct file *file, void __user *arg, int ring)
struct igb_private_data *igb_priv = file->private_data;
struct igb_adapter *adapter;
struct igb_buf_cmd req;
+ /*size used for the purpose of copying the contents of igb_buf_cmd
+ between userspace and kernel space
+ introduced to handle possible mismatch in libigb and igb version*/
+ int buf_cmd_size = 0;
int err = 0;
struct page *page;
dma_addr_t page_dma;
struct igb_user_page *userpage;
+
if (igb_priv == NULL) {
printk("cannot find private data!\n");
return -ENOENT;
@@ -10325,7 +10389,22 @@ static long igb_mapbuf_user(struct file *file, void __user *arg, int ring)
return -ENOENT;
}
- if (copy_from_user(&req, arg, sizeof(req)))
+ if(ring != IGB_IOCTL_MAPBUF)
+ {
+ dev_warn(&adapter->pdev->dev, "Old ioctl value used: %d, consider using a new one from libigb \n", ring);
+ /* this situation suggest using an old ioctl by libigb
+ as a consequence the igb_buf_cmd struct from libigb perspective does not contain the "pa" field
+ we need to align the requested size in copy_from_user() for possibility */
+ buf_cmd_size = sizeof(req) - sizeof(u64);
+ } else {
+ /* assuming no compatibility issue:
+ libigb and kernel module have the same
+ igb_buf_cmd structs ("pa" field included in both)
+ */
+ buf_cmd_size = sizeof(req);
+ }
+
+ if (copy_from_user(&req, arg, buf_cmd_size))
return -EFAULT;
userpage = vzalloc(sizeof(struct igb_user_page));
@@ -10368,11 +10447,14 @@ static long igb_mapbuf_user(struct file *file, void __user *arg, int ring)
igb_priv->userpages->page = page;
igb_priv->userpages->page_dma = page_dma;
+ if(ring == IGB_IOCTL_MAPBUF)
+ req.pa = page_to_phys(page);
+
req.physaddr = page_dma;
req.mmap_size = PAGE_SIZE;
mutex_unlock(&adapter->lock);
- if (copy_to_user(arg, &req, sizeof(req))) {
+ if (copy_to_user(arg, &req, buf_cmd_size)) {
printk("copyout to user failed\n");
err = -EFAULT;
mutex_lock(&adapter->lock);
@@ -10405,15 +10487,17 @@ static long igb_mapbuf(struct file *file, void __user *arg, int ring)
struct igb_private_data *igb_priv = file->private_data;
struct igb_adapter *adapter;
struct igb_buf_cmd req;
+ /*size used for the purpose of copying the contents of igb_buf_cmd
+ between userspace and kernel space
+ introduced to handle possible mismatch in libigb and igb version*/
+ int buf_cmd_size = 0;
+
int err = 0;
if (igb_priv == NULL) {
printk("cannot find private data!\n");
return -ENOENT;
- }
-
- if (copy_from_user(&req, arg, sizeof(req)))
- return -EFAULT;
+ }
adapter = igb_priv->adapter;
if (adapter == NULL) {
@@ -10421,7 +10505,29 @@ static long igb_mapbuf(struct file *file, void __user *arg, int ring)
return -ENOENT;
}
- if ((ring == IGB_MAPRING) || (ring == IGB_MAP_TX_RING)) {
+ if((ring != IGB_IOCTL_MAP_TX_RING) && (ring != IGB_IOCTL_MAP_RX_RING))
+ {
+ dev_warn(&adapter->pdev->dev, "Old ioctl value used: %d, consider using new one from libigb \n", ring);
+ /* this situation suggest using an old ioctl by libigb
+ as a consequence the igb_buf_cmd struct from libigb perspective does not contain the "pa" field
+ we need to align the requested size in copy_from_user() for possibility */
+ buf_cmd_size = sizeof(req) - sizeof(u64);
+
+ } else {
+
+ /* assuming no compatibility issue:
+ libigb and kernel module have the same
+ igb_buf_cmd structs ("pa" field included in both)
+ */
+ buf_cmd_size = sizeof(req);
+
+ }
+
+ if (copy_from_user(&req, arg, buf_cmd_size))
+ return -EFAULT;
+
+ if ((ring == IGB_MAPRING) || (ring == IGB_MAP_TX_RING) ||
+ ring == IGB_IOCTL_MAP_TX_RING) {
if (req.queue >= 3) {
printk("mapring:invalid queue specified(%d)\n",
req.queue);
@@ -10443,10 +10549,13 @@ static long igb_mapbuf(struct file *file, void __user *arg, int ring)
adapter->uring_tx_init |= (1 << req.queue);
igb_priv->uring_tx_init |= (1 << req.queue);
+ if(ring == IGB_IOCTL_MAP_TX_RING)
+ req.pa = virt_to_phys(adapter->tx_ring[req.queue]->desc);
+
req.physaddr = adapter->tx_ring[req.queue]->dma;
req.mmap_size = adapter->tx_ring[req.queue]->size;
mutex_unlock(&adapter->lock);
- } else if (ring == IGB_MAP_RX_RING) {
+ } else if ((ring == IGB_MAP_RX_RING) || (ring == IGB_IOCTL_MAP_RX_RING)) {
if (req.queue >= 3) {
printk("mapring:invalid queue specified(%d)\n",
req.queue);
@@ -10467,6 +10576,9 @@ static long igb_mapbuf(struct file *file, void __user *arg, int ring)
adapter->uring_rx_init |= (1 << req.queue);
igb_priv->uring_rx_init |= (1 << req.queue);
+
+ if(ring == IGB_IOCTL_MAP_RX_RING)
+ req.pa = virt_to_phys(adapter->rx_ring[req.queue]->desc);
req.physaddr = adapter->rx_ring[req.queue]->dma;
req.mmap_size = adapter->rx_ring[req.queue]->size;
@@ -10476,7 +10588,7 @@ static long igb_mapbuf(struct file *file, void __user *arg, int ring)
return -EINVAL;
}
- if (copy_to_user(arg, &req, sizeof(req))) {
+ if (copy_to_user(arg, &req, buf_cmd_size)) {
printk("copyout to user failed\n");
err = -EFAULT;
goto failed;
@@ -10494,22 +10606,36 @@ static long igb_unmapbuf(struct file *file, void __user *arg, int ring)
struct igb_private_data *igb_priv = file->private_data;
struct igb_adapter *adapter;
struct igb_buf_cmd req;
+ int buf_cmd_size = 0;
if (igb_priv == NULL) {
printk("cannot find private data!\n");
return -ENOENT;
}
- if (copy_from_user(&req, arg, sizeof(req)))
- return -EFAULT;
-
adapter = igb_priv->adapter;
if (adapter == NULL) {
printk("map to unbound device!\n");
return -ENOENT;
}
- if ((ring == IGB_UNMAP_TX_RING)) {
+
+ if((ring != IGB_IOCTL_UNMAPBUF) && (ring != IGB_IOCTL_UNMAP_TX_RING) &&
+ (ring != IGB_IOCTL_UNMAP_RX_RING)) {
+
+ dev_warn(&adapter->pdev->dev, "Old ioctl number used: %d, consider using new one from libigb \n", ring);
+ buf_cmd_size = sizeof(req) - sizeof(u64);
+
+ } else {
+
+ buf_cmd_size = sizeof(req);
+ }
+
+ if (copy_from_user(&req, arg, buf_cmd_size))
+ return -EFAULT;
+
+
+ if ((ring == IGB_UNMAP_TX_RING) || (ring == IGB_IOCTL_UNMAP_TX_RING)) {
/* its easy to figure out what to free on the rings ... */
if (req.queue >= 3)
return -EINVAL;
@@ -10527,7 +10653,7 @@ static long igb_unmapbuf(struct file *file, void __user *arg, int ring)
adapter->uring_tx_init &= ~(1 << req.queue);
igb_priv->uring_tx_init &= ~(1 << req.queue);
mutex_unlock(&adapter->lock);
- } else if (ring == IGB_UNMAP_RX_RING) {
+ } else if ((ring == IGB_UNMAP_RX_RING) || (ring == IGB_IOCTL_UNMAP_RX_RING)) {
/* its easy to figure out what to free on the rings ... */
if (req.queue >= 3)
return -EINVAL;
@@ -10601,14 +10727,20 @@ static long igb_ioctl_file(struct file *file, unsigned int cmd,
break;
case IGB_MAP_TX_RING:
case IGB_MAP_RX_RING:
+ case IGB_IOCTL_MAP_TX_RING:
+ case IGB_IOCTL_MAP_RX_RING:
err = igb_mapbuf(file, argp, cmd);
break;
case IGB_MAPBUF:
+ case IGB_IOCTL_MAPBUF:
err = igb_mapbuf_user(file, argp, cmd);
break;
case IGB_UNMAP_TX_RING:
case IGB_UNMAP_RX_RING:
case IGB_UNMAPBUF:
+ case IGB_IOCTL_UNMAPBUF:
+ case IGB_IOCTL_UNMAP_TX_RING:
+ case IGB_IOCTL_UNMAP_RX_RING:
err = igb_unmapbuf(file, argp, cmd);
break;
case IGB_LINKSPEED:
@@ -10701,8 +10833,11 @@ static void igb_vm_open(struct vm_area_struct *vma)
static void igb_vm_close(struct vm_area_struct *vma)
{
}
-
+#if LINUX_VERSION_CODE >= KERNEL_VERSION(4,11,0)
+static int igb_vm_fault(struct vm_fault *fdata)
+#else
static int igb_vm_fault(struct vm_area_struct *area, struct vm_fault *fdata)
+#endif
{
return VM_FAULT_SIGBUS;
}