| From: Sebastian Siewior <bigeasy@linutronix.de> |
| Subject: net/cpsw: giant cpsw patch |
| |
| This patch contains: |
| git diff v3.8..net-merge drivers/net/ethernet/ti arch/arm/boot/dts/am33* include/linux/platform_data/cpsw.h |
| where the net-merge branch contains the following branches merged: |
| net-next as of 37fe066 net: fix address check in rtnl_fdb_del |
| net as of b9e48de isdn/sc: Fix incorrect module_param_array types |
| linus as of 697dfd8 Merge tag 'efi-urgent' into x86/urgent |
| |
| including the following patches: |
| |
| |commit 15c6ff3bc0ff3464a8c7efcdea09c86454571622 |
| |Author: Jiri Pirko <jiri@resnulli.us> |
| |Date: Tue Jan 1 03:30:17 2013 +0000 |
| | |
| | net: remove unnecessary NET_ADDR_RANDOM "bitclean" |
| | |
| | NET_ADDR_SET is set in dev_set_mac_address() no need to alter |
| | dev->addr_assign_type value in drivers. |
| | |
| | Signed-off-by: Jiri Pirko <jiri@resnulli.us> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 7826d43f2db45c9305a6e0ba165650e1a203f517 |
| |Author: Jiri Pirko <jiri@resnulli.us> |
| |Date: Sun Jan 6 00:44:26 2013 +0000 |
| | |
| | ethtool: fix drvinfo strings set in drivers |
| | |
| | Use strlcpy where possible to ensure the string is \0 terminated. |
| | Use always sizeof(string) instead of 32, ETHTOOL_BUSINFO_LEN |
| | and custom defines. |
| | Use snprintf instead of sprint. |
| | Remove unnecessary inits of ->fw_version |
| | Remove unnecessary inits of drvinfo struct. |
| | |
| | Signed-off-by: Jiri Pirko <jiri@resnulli.us> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 8ff25eebb8161d08ddc48539e6b4afa0b18d778f |
| |Author: Kees Cook <keescook@chromium.org> |
| |Date: Tue Oct 2 11:18:24 2012 -0700 |
| | |
| | drivers/net/ethernet/ti: remove depends on CONFIG_EXPERIMENTAL |
| | |
| | The CONFIG_EXPERIMENTAL config item has not carried much meaning for a |
| | while now and is almost always enabled by default. As agreed during the |
| | Linux kernel summit, remove it from any "depends on" lines in Kconfigs. |
| | |
| | CC: Tony Lindgren <tony@atomide.com> |
| | CC: Mugunthan V N <mugunthanvnm@ti.com> |
| | CC: Kevin Hilman <khilman@ti.com> |
| | CC: "David S. Miller" <davem@davemloft.net> |
| | CC: Cyril Chemparathy <cyril@ti.com> |
| | Signed-off-by: Kees Cook <keescook@chromium.org> |
| | Acked-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit f9a8f83b04e0c362a2fc660dbad980d24af209fc |
| |Author: Florian Fainelli <florian@openwrt.org> |
| |Date: Mon Jan 14 00:52:52 2013 +0000 |
| | |
| | net: phy: remove flags argument from phy_{attach, connect, connect_direct} |
| | |
| | The flags argument of the phy_{attach,connect,connect_direct} functions |
| | is then used to assign a struct phy_device dev_flags with its value. |
| | All callers but the tg3 driver pass the flag 0, which results in the |
| | underlying PHY drivers in drivers/net/phy/ not being able to actually |
| | use any of the flags they would set in dev_flags. This patch gets rid of |
| | the flags argument, and passes phydev->dev_flags to the internal PHY |
| | library call phy_attach_direct() such that drivers which actually modify |
| | a phy device dev_flags get the value preserved for use by the underlying |
| | phy driver. |
| | |
| | Acked-by: Kosta Zertsekel <konszert@marvell.com> |
| | Signed-off-by: Florian Fainelli <florian@openwrt.org> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit fae50823d0ee579e006a7ba2b20880e354388b25 |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Thu Jan 17 06:31:34 2013 +0000 |
| | |
| | net: ethernet: davinci_cpdma: Add boundary for rx and tx descriptors |
| | |
| | When there is heavy transmission traffic in the CPDMA, then Rx descriptors |
| | memory is also utilized as tx desc memory looses all rx descriptors and the |
| | driver stops working then. |
| | |
| | This patch adds boundary for tx and rx descriptors in bd ram dividing the |
| | descriptor memory to ensure that during heavy transmission tx doesn't use |
| | rx descriptors. |
| | |
| | This patch is already applied to davinci_emac driver, since CPSW and |
| | davici_dmac shares the same CPDMA, moving the boundry seperation from |
| | Davinci EMAC driver to CPDMA driver which was done in the following |
| | commit |
| | |
| | commit 86d8c07ff2448eb4e860e50f34ef6ee78e45c40c |
| | Author: Sascha Hauer <s.hauer@pengutronix.de> |
| | Date: Tue Jan 3 05:27:47 2012 +0000 |
| | |
| | net/davinci: do not use all descriptors for tx packets |
| | |
| | The driver uses a shared pool for both rx and tx descriptors. |
| | During open it queues fixed number of 128 descriptors for receive |
| | packets. For each received packet it tries to queue another |
| | descriptor. If this fails the descriptor is lost for rx. |
| | The driver has no limitation on tx descriptors to use, so it |
| | can happen during a nmap / ping -f attack that the driver |
| | allocates all descriptors for tx and looses all rx descriptors. |
| | The driver stops working then. |
| | To fix this limit the number of tx descriptors used to half of |
| | the descriptors available, the rx path uses the other half. |
| | |
| | Tested on a custom board using nmap / ping -f to the board from |
| | two different hosts. |
| | |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 7373470202a3c98e1a338bf1acf51247cd100868 |
| |Author: Thierry Reding <thierry.reding@avionic-design.de> |
| |Date: Mon Jan 21 10:38:39 2013 +0100 |
| | |
| | net: ethernet: davinci: Fix build breakage |
| | |
| | The correct name of the transmit DMA channel field in struct emac_priv |
| | is txchan, not txch. |
| | |
| | Signed-off-by: Thierry Reding <thierry.reding@avionic-design.de> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit b2adaca92c63b9bb8beb021d554f656e387a7648 |
| |Author: Joe Perches <joe@perches.com> |
| |Date: Sun Feb 3 17:43:58 2013 +0000 |
| | |
| | ethernet: Remove unnecessary alloc/OOM messages, alloc cleanups |
| | |
| | alloc failures already get standardized OOM |
| | messages and a dump_stack. |
| | |
| | Convert kzalloc's with multiplies to kcalloc. |
| | Convert kmalloc's with multiplies to kmalloc_array. |
| | Fix a few whitespace defects. |
| | Convert a constant 6 to ETH_ALEN. |
| | Use parentheses around sizeof. |
| | Convert vmalloc/memset to vzalloc. |
| | Remove now unused size variables. |
| | |
| | Signed-off-by: Joe Perches <joe@perches.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit e11b220f336c654db876027d40953acef90b0cae |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Tue Feb 5 08:26:47 2013 +0000 |
| | |
| | drivers: net: cpsw: Add helper functions for VLAN ALE implementation |
| | |
| | Add helper functions for VLAN ALE implementations for Add, Delete |
| | Dump VLAN related ALE entries |
| | |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 3b72c2fe0c6bbec42ed7f899931daef227b80322 |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Tue Feb 5 08:26:48 2013 +0000 |
| | |
| | drivers: net:ethernet: cpsw: add support for VLAN |
| | |
| | adding support for VLAN interface for cpsw. |
| | |
| | CPSW VLAN Capability |
| | * Can filter VLAN packets in Hardware |
| | |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit f6575c90f6fc637697f130ea4a05892296c9a473 |
| |Author: Vaibhav Bedia <vaibhav.bedia@ti.com> |
| |Date: Tue Jan 29 16:45:07 2013 +0530 |
| | |
| | ARM: DTS: AM33XX: Add nodes for OCMC RAM and WKUP-M3 |
| | |
| | Since AM33XX supports only DT-boot, this is needed |
| | for the appropriate device nodes to be created. |
| | |
| | Note: OCMC RAM is part of the PER power domain and supports |
| | retention. The assembly code for low power entry/exit will |
| | run from OCMC RAM. To ensure that the OMAP PM code does not |
| | attempt to disable the clock to OCMC RAM as part of the |
| | suspend process add the no_idle_on_suspend flag. |
| | |
| | Signed-off-by: Vaibhav Bedia <vaibhav.bedia@ti.com> |
| | Acked-by: Santosh Shilimkar <santosh.shilimkar@ti.com> |
| | Acked-by: Peter Korsgaard <jacmet@sunsite.dk> |
| | Signed-off-by: Paul Walmsley <paul@pwsan.com> |
| | |
| |commit f6e135c81eeb648c6addc6aeff2ee80f28ea413b |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Mon Feb 11 09:52:18 2013 +0000 |
| | |
| | driver: net: ethernet: davinci_cpdma: add support for directed packet and source port detection |
| | |
| | * Introduced parameter to add port number for directed packet in cpdma_chan_submit |
| | * Source port detection macro with DMA descriptor status |
| | |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 9232b16df2167c8afcb89de39ee85f5091ebacff |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Mon Feb 11 09:52:19 2013 +0000 |
| | |
| | driver: net: ethernet: cpsw: make cpts as pointer |
| | |
| | As CPTS is common module for both EMAC in Dual EMAC mode so making cpts as |
| | pointer. |
| | |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit d9ba8f9e6298af71ec1c1fd3d88c3ef68abd0ec3 |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Mon Feb 11 09:52:20 2013 +0000 |
| | |
| | driver: net: ethernet: cpsw: dual emac interface implementation |
| | |
| | The CPSW switch can act as Dual EMAC by segregating the switch ports |
| | using VLAN and port VLAN as per the TRM description in |
| | 14.3.2.10.2 Dual Mac Mode |
| | |
| | Following CPSW components will be common for both the interfaces. |
| | * Interrupt source is common for both eth interfaces |
| | * Interrupt pacing is common for both interfaces |
| | * Hardware statistics is common for all the ports |
| | * CPDMA is common for both eth interface |
| | * CPTS is common for both the interface and it should not be enabled on |
| | both the interface as timestamping information doesn't contain port |
| | information. |
| | |
| | Constrains |
| | * Reserved VID of One port should not be used in other interface which will |
| | enable switching functionality |
| | * Same VID must not be used in both the interface which will enable switching |
| | functionality |
| | |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 79876e0394aa46e74267a5871c4f4469544dcacf |
| |Author: Cyril Roelandt <tipecaml@gmail.com> |
| |Date: Tue Feb 12 12:52:30 2013 +0000 |
| | |
| | net: ethernet: ti: remove redundant NULL check. |
| | |
| | cpdma_chan_destroy() on a NULL pointer is a no-op, so the NULL check in |
| | cpdma_ctlr_destroy() can safely be removed. |
| | |
| | Signed-off-by: Cyril Roelandt <tipecaml@gmail.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 6929e24e4cc46ce8d5b7dd8f8bdf4244c8d77f76 |
| |Author: Arnd Bergmann <arnd@arndb.de> |
| |Date: Thu Feb 14 17:53:01 2013 +0100 |
| | |
| | net: cwdavinci_cpdma: export symbols for cpsw |
| | |
| | With the support for ARM AM33xx in multiplatform kernels |
| | in 3.9, an older bug appears in ARM allmodconfig: |
| | When the cpsw driver is built as a module with cpdma |
| | support enabled, it uses symbols that the cpdma driver |
| | does not export. |
| | |
| | Without this patch, building allmodconfig results in: |
| | |
| | ERROR: "cpdma_ctlr_int_ctrl" [drivers/net/ethernet/ti/ti_cpsw.ko] undefined! |
| | ERROR: "cpdma_control_set" [drivers/net/ethernet/ti/ti_cpsw.ko] undefined! |
| | ERROR: "cpdma_ctlr_eoi" [drivers/net/ethernet/ti/ti_cpsw.ko] undefined! |
| | |
| | Signed-off-by: Arnd Bergmann <arnd@arndb.de> |
| | Acked-by: David S. Miller <davem@davemloft.net> |
| | Cc: Mugunthan V N <mugunthanvnm@ti.com> |
| | Cc: Vaibhav Hiremath <hvaibhav@ti.com> |
| | Cc: Richard Cochran <richardcochran@gmail.com> |
| | Cc: netdev@vger.kernel.org |
| | |
| |commit 510a1e7249298f6bbd049e1ec98041ddf5ef6452 |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Sun Feb 17 22:19:20 2013 +0000 |
| | |
| | drivers: net: davinci_cpdma: acknowledge interrupt properly |
| | |
| | CPDMA interrupts are not properly acknowledged which leads to interrupt |
| | storm, only cpdma interrupt 0 is acknowledged in Davinci CPDMA driver. |
| | Changed cpdma_ctlr_eoi api to acknowledge 1 and 2 interrupts which are |
| | used for rx and tx respectively. |
| | |
| | Reported-by: Pantelis Antoniou <panto@antoniou-consulting.com> |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 06991c28f37ad68e5c03777f5c3b679b56e3dac1 |
| |Merge: 460dc1e 74fef7a |
| |Author: Linus Torvalds <torvalds@linux-foundation.org> |
| |Date: Thu Feb 21 12:05:51 2013 -0800 |
| | |
| | Merge tag 'driver-core-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core |
| | |
| | Pull driver core patches from Greg Kroah-Hartman: |
| | "Here is the big driver core merge for 3.9-rc1 |
| | |
| | There are two major series here, both of which touch lots of drivers |
| | all over the kernel, and will cause you some merge conflicts: |
| | |
| | - add a new function called devm_ioremap_resource() to properly be |
| | able to check return values. |
| | |
| | - remove CONFIG_EXPERIMENTAL |
| | |
| | Other than those patches, there's not much here, some minor fixes and |
| | updates" |
| | |
| | Fix up trivial conflicts |
| | |
| | * tag 'driver-core-3.9-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/gregkh/driver-core: (221 commits) |
| | base: memory: fix soft/hard_offline_page permissions |
| | drivercore: Fix ordering between deferred_probe and exiting initcalls |
| | backlight: fix class_find_device() arguments |
| | TTY: mark tty_get_device call with the proper const values |
| | driver-core: constify data for class_find_device() |
| | firmware: Ignore abort check when no user-helper is used |
| | firmware: Reduce ifdef CONFIG_FW_LOADER_USER_HELPER |
| | firmware: Make user-mode helper optional |
| | firmware: Refactoring for splitting user-mode helper code |
| | Driver core: treat unregistered bus_types as having no devices |
| | watchdog: Convert to devm_ioremap_resource() |
| | thermal: Convert to devm_ioremap_resource() |
| | spi: Convert to devm_ioremap_resource() |
| | power: Convert to devm_ioremap_resource() |
| | mtd: Convert to devm_ioremap_resource() |
| | mmc: Convert to devm_ioremap_resource() |
| | mfd: Convert to devm_ioremap_resource() |
| | media: Convert to devm_ioremap_resource() |
| | iommu: Convert to devm_ioremap_resource() |
| | drm: Convert to devm_ioremap_resource() |
| | ... |
| | |
| |commit 3298a3511f1e73255a8dc023efd909e569eea037 |
| |Merge: 5ce7aba acb7452 |
| |Author: Linus Torvalds <torvalds@linux-foundation.org> |
| |Date: Thu Feb 21 15:20:41 2013 -0800 |
| | |
| | Merge tag 'multiplatform' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc |
| | |
| | Pull ARM SoC multiplatform support from Arnd Bergmann: |
| | "Converting more ARM platforms to multiplatform support. This time, |
| | OMAP gets converted, which is a major step since this is by far the |
| | largest platform in terms of code size. The same thing happens to the |
| | vt8500 platform." |
| | |
| | * tag 'multiplatform' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: |
| | net: cwdavinci_cpdma: export symbols for cpsw |
| | remoteproc: omap: depend on OMAP_MBOX_FWK |
| | [media] davinci: do not include mach/hardware.h |
| | ARM: OMAP2+: Make sure files with omap initcalls include soc.h |
| | ARM: OMAP2+: Include soc.h to drm.c to fix compiling |
| | ARM: OMAP2+: Fix warning for hwspinlock omap_postcore_initcall |
| | ARM: multi_v7_defconfig: add ARCH_ZYNQ |
| | ARM: multi_v7_defconfig: remove unnecessary CONFIG_GPIOLIB |
| | arm: vt8500: Remove remaining mach includes |
| | arm: vt8500: Convert debug-macro.S to be multiplatform friendly |
| | arm: vt8500: Remove single platform Kconfig options |
| | ARM: OMAP2+: Remove now obsolete uncompress.h and debug-macro.S |
| | ARM: OMAP2+: Add minimal support for booting vexpress |
| | ARM: OMAP2+: Enable ARCH_MULTIPLATFORM support |
| | ARM: OMAP2+: Disable code that currently does not work with multiplaform |
| | ARM: OMAP2+: Add multiplatform debug_ll support |
| | ARM: OMAP: Fix dmaengine init for multiplatform |
| | ARM: OMAP: Fix i2c cmdline initcall for multiplatform |
| | ARM: OMAP2+: Use omap initcalls |
| | ARM: OMAP2+: Limit omap initcalls to omap only on multiplatform kernels |
| | |
| |commit 0237c11044b3670adcbe80cd6dd721285347f497 |
| |Author: Daniel Mack <zonque@gmail.com> |
| |Date: Tue Feb 26 04:06:20 2013 +0000 |
| | |
| | drivers: net: ethernet: cpsw: consider number of slaves in interation |
| | |
| | Make cpsw_add_default_vlan() look at the actual number of slaves for its |
| | iteration, so boards with less than 2 slaves don't ooops at boot. |
| | |
| | Signed-off-by: Daniel Mack <zonque@gmail.com> |
| | Cc: Mugunthan V N <mugunthanvnm@ti.com> |
| | Cc: David S. Miller <davem@davemloft.net> |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 7307c00f335a4e986586b12334696098d2fc2bcd |
| |Merge: f8f466c 55ccb1a |
| |Author: Linus Torvalds <torvalds@linux-foundation.org> |
| |Date: Thu Feb 28 20:00:40 2013 -0800 |
| | |
| | Merge tag 'late-omap' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc |
| | |
| | Pull ARM SoC late OMAP changes from Olof Johansson: |
| | "This branch contains changes for OMAP that came in late during the |
| | release staging, close to when the merge window opened. |
| | |
| | It contains, among other things: |
| | |
| | - OMAP PM fixes and some patches for audio device integration |
| | - OMAP clock fixes related to common clock conversion |
| | - A set of patches cleaning up WFI entry and blocking. |
| | - A set of fixes and IP block support for PM on TI AM33xx SoCs |
| | (Beaglebone, etc) |
| | - A set of smaller fixes and cleanups around AM33xx restart and |
| | revision detection, as well as removal of some dead code |
| | (CONFIG_32K_TIMER_HZ)" |
| | |
| | * tag 'late-omap' of git://git.kernel.org/pub/scm/linux/kernel/git/arm/arm-soc: (34 commits) |
| | ARM: omap2: include linux/errno.h in hwmod_reset |
| | ARM: OMAP2+: fix some omap_device_build() calls that aren't compiled by default |
| | ARM: OMAP4: hwmod data: Enable AESS hwmod device |
| | ARM: OMAP4: hwmod data: Update AESS data with memory bank area |
| | ARM: OMAP4+: AESS: enable internal auto-gating during initial setup |
| | ASoC: TI AESS: add autogating-enable function, callable from architecture code |
| | ARM: OMAP2+: hwmod: add enable_preprogram hook |
| | ARM: OMAP4: clock data: Add missing clkdm association for dpll_usb |
| | ARM: OMAP2+: PM: Fix the dt return condition in pm_late_init() |
| | ARM: OMAP2: am33xx-hwmod: Fix "register offset NULL check" bug |
| | ARM: OMAP2+: AM33xx: hwmod: add missing HWMOD_NO_IDLEST flags |
| | ARM: OMAP: AM33xx hwmod: Add parent-child relationship for PWM subsystem |
| | ARM: OMAP: AM33xx hwmod: Corrects PWM subsystem HWMOD entries |
| | ARM: DTS: AM33XX: Add nodes for OCMC RAM and WKUP-M3 |
| | ARM: OMAP2+: AM33XX: Update the hardreset API |
| | ARM: OMAP2+: AM33XX: hwmod: Update the WKUP-M3 hwmod with reset status bit |
| | ARM: OMAP2+: AM33XX: hwmod: Fixup cpgmac0 hwmod entry |
| | ARM: OMAP2+: AM33XX: hwmod: Update TPTC0 hwmod with the right flags |
| | ARM: OMAP2+: AM33XX: hwmod: Register OCMC RAM hwmod |
| | ARM: OMAP2+: AM33XX: CM/PRM: Use __ASSEMBLER__ macros in header files |
| | ... |
| | |
| |commit 9da060d0ed571bbff434c4a1ef3e48db99a37ee0 |
| |Merge: e3b5951 aab2b4b |
| |Author: Linus Torvalds <torvalds@linux-foundation.org> |
| |Date: Tue Mar 5 18:42:29 2013 -0800 |
| | |
| | Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net |
| | |
| | Pull networking fixes from David Miller: |
| | "A moderately sized pile of fixes, some specifically for merge window |
| | introduced regressions although others are for longer standing items |
| | and have been queued up for -stable. |
| | |
| | I'm kind of tired of all the RDS protocol bugs over the years, to be |
| | honest, it's way out of proportion to the number of people who |
| | actually use it. |
| | |
| | 1) Fix missing range initialization in netfilter IPSET, from Jozsef |
| | Kadlecsik. |
| | |
| | 2) ieee80211_local->tim_lock needs to use BH disabling, from Johannes |
| | Berg. |
| | |
| | 3) Fix DMA syncing in SFC driver, from Ben Hutchings. |
| | |
| | 4) Fix regression in BOND device MAC address setting, from Jiri |
| | Pirko. |
| | |
| | 5) Missing usb_free_urb in ISDN Hisax driver, from Marina Makienko. |
| | |
| | 6) Fix UDP checksumming in bnx2x driver for 57710 and 57711 chips, |
| | fix from Dmitry Kravkov. |
| | |
| | 7) Missing cfgspace_lock initialization in BCMA driver. |
| | |
| | 8) Validate parameter size for SCTP assoc stats getsockopt(), from |
| | Guenter Roeck. |
| | |
| | 9) Fix SCTP association hangs, from Lee A Roberts. |
| | |
| | 10) Fix jumbo frame handling in r8169, from Francois Romieu. |
| | |
| | 11) Fix phy_device memory leak, from Petr Malat. |
| | |
| | 12) Omit trailing FCS from frames received in BGMAC driver, from Hauke |
| | Mehrtens. |
| | |
| | 13) Missing socket refcount release in L2TP, from Guillaume Nault. |
| | |
| | 14) sctp_endpoint_init should respect passed in gfp_t, rather than use |
| | GFP_KERNEL unconditionally. From Dan Carpenter. |
| | |
| | 15) Add AISX AX88179 USB driver, from Freddy Xin. |
| | |
| | 16) Remove MAINTAINERS entries for drivers deleted during the merge |
| | window, from Cesar Eduardo Barros. |
| | |
| | 17) RDS protocol can try to allocate huge amounts of memory, check |
| | that the user's request length makes sense, from Cong Wang. |
| | |
| | 18) SCTP should use the provided KMALLOC_MAX_SIZE instead of it's own, |
| | bogus, definition. From Cong Wang. |
| | |
| | 19) Fix deadlocks in FEC driver by moving TX reclaim into NAPI poll, |
| | from Frank Li. Also, fix a build error introduced in the merge |
| | window. |
| | |
| | 20) Fix bogus purging of default routes in ipv6, from Lorenzo Colitti. |
| | |
| | 21) Don't double count RTT measurements when we leave the TCP receive |
| | fast path, from Neal Cardwell." |
| | |
| | * git://git.kernel.org/pub/scm/linux/kernel/git/davem/net: (61 commits) |
| | tcp: fix double-counted receiver RTT when leaving receiver fast path |
| | CAIF: fix sparse warning for caif_usb |
| | rds: simplify a warning message |
| | net: fec: fix build error in no MXC platform |
| | net: ipv6: Don't purge default router if accept_ra=2 |
| | net: fec: put tx to napi poll function to fix dead lock |
| | sctp: use KMALLOC_MAX_SIZE instead of its own MAX_KMALLOC_SIZE |
| | rds: limit the size allocated by rds_message_alloc() |
| | MAINTAINERS: remove eexpress |
| | MAINTAINERS: remove drivers/net/wan/cycx* |
| | MAINTAINERS: remove 3c505 |
| | caif_dev: fix sparse warnings for caif_flow_cb |
| | ax88179_178a: ASIX AX88179_178A USB 3.0/2.0 to gigabit ethernet adapter driver |
| | sctp: use the passed in gfp flags instead GFP_KERNEL |
| | ipv[4|6]: correct dropwatch false positive in local_deliver_finish |
| | l2tp: Restore socket refcount when sendmsg succeeds |
| | net/phy: micrel: Disable asymmetric pause for KSZ9021 |
| | bgmac: omit the fcs |
| | phy: Fix phy_device_free memory leak |
| | bnx2x: Fix KR2 work-around condition |
| | ... |
| | |
| |commit 720a43efd30f04a0a492c85fb997361c44fbae05 |
| |Author: Joe Perches <joe@perches.com> |
| |Date: Fri Mar 8 15:03:25 2013 +0000 |
| | |
| | drivers:net: Remove unnecessary OOM messages after netdev_alloc_skb |
| | |
| | Emitting netdev_alloc_skb and netdev_alloc_skb_ip_align OOM |
| | messages is unnecessary as there is already a dump_stack |
| | after allocation failures. |
| | |
| | Other trivial changes around these removals: |
| | |
| | Convert a few comparisons of pointer to 0 to !pointer. |
| | Change flow to remove unnecessary label. |
| | Remove now unused variable. |
| | Hoist assignment from if. |
| | |
| | Signed-off-by: Joe Perches <joe@perches.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit e86ac13b031cf71d8f40ff513e627aac80e6b765 |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Mon Mar 11 23:16:35 2013 +0000 |
| | |
| | drivers: net: ethernet: cpsw: change cpts_active_slave to active_slave |
| | |
| | Change cpts_active_slave to active_slave so that the same DT property |
| | can be used to ethtool and SIOCGMIIPHY. |
| | |
| | CC: Richard Cochran <richardcochran@gmail.com> |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit d3bb9c58b567d240eaaa2dc8bd778696eaed5fbd |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Mon Mar 11 23:16:36 2013 +0000 |
| | |
| | driver: net: ethernet: cpsw: implement ethtool get/set phy setting |
| | |
| | This patch implements get/set of the phy settings via ethtool apis |
| | |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit ff5b8ef2ef3af0fd7e1cf6c8c1ed9ec5afbda422 |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Mon Mar 11 23:16:37 2013 +0000 |
| | |
| | driver: net: ethernet: cpsw: implement interrupt pacing via ethtool |
| | |
| | This patch implements support for interrupt pacing block of CPSW via ethtool |
| | Inetrrupt pacing block is common of both the ethernet interface in |
| | dual emac mode |
| | |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 11f2c988382b880e602a005c26436043c5d2c274 |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Mon Mar 11 23:16:38 2013 +0000 |
| | |
| | drivers: net: ethernet: cpsw: implement get phy_id via ioctl |
| | |
| | Implement get phy_id via ioctl SIOCGMIIPHY. In switch mode active phy_id |
| | is returned and in dual EMAC mode slave's specific phy_id is returned. |
| | |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit d35162f89b8f00537d7b240b76d2d0e8b8d29aa0 |
| |Author: Daniel Mack <zonque@gmail.com> |
| |Date: Tue Mar 12 06:31:19 2013 +0000 |
| | |
| | net: ethernet: cpsw: fix usage of cpdma_check_free_tx_desc() |
| | |
| | Commit fae50823d0 ("net: ethernet: davinci_cpdma: Add boundary for rx |
| | and tx descriptors") introduced a function to check the current |
| | allocation state of tx packets. The return value is taken into account |
| | to stop the netqork queue on the adapter in case there are no free |
| | slots. |
| | |
| | However, cpdma_check_free_tx_desc() returns 'true' if there is room in |
| | the bitmap, not 'false', so the usage of the function is wrong. |
| | |
| | Signed-off-by: Daniel Mack <zonque@gmail.com> |
| | Cc: Mugunthan V N <mugunthanvnm@ti.com> |
| | Reported-by: Sven Neumann <s.neumann@raumfeld.com> |
| | Reported-by: Andreas Fenkart <andreas.fenkart@streamunlimited.com> |
| | Tested-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Tested-by: Andreas Fenkart <andreas.fenkart@streamunlimited.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 75b9b61bb8a18e75afe7b10dd55681e748fa27df |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Fri Mar 15 04:10:16 2013 +0000 |
| | |
| | drivers: net: ethernet: ti: davinci_emac: fix usage of cpdma_check_free_tx_desc() |
| | |
| | Fix which was done in the following commit in cpsw driver has |
| | to be taken forward to davinci emac driver as well. |
| | |
| | commit d35162f89b8f00537d7b240b76d2d0e8b8d29aa0 |
| | Author: Daniel Mack <zonque@gmail.com> |
| | Date: Tue Mar 12 06:31:19 2013 +0000 |
| | |
| | net: ethernet: cpsw: fix usage of cpdma_check_free_tx_desc() |
| | |
| | Commit fae50823d0 ("net: ethernet: davinci_cpdma: Add boundary for rx |
| | and tx descriptors") introduced a function to check the current |
| | allocation state of tx packets. The return value is taken into account |
| | to stop the netqork queue on the adapter in case there are no free |
| | slots. |
| | |
| | However, cpdma_check_free_tx_desc() returns 'true' if there is room in |
| | the bitmap, not 'false', so the usage of the function is wrong. |
| | |
| | Reported-by: Prabhakar Lad <prabhakar.csengg@gmail.com> |
| | Tested-by: Prabhakar Lad <prabhakar.csengg@gmail.com> |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 61816596d1c9026d0ecb20c44f90452c41596ffe |
| |Merge: 23a9072 da2191e |
| |Author: David S. Miller <davem@davemloft.net> |
| |Date: Wed Mar 20 12:46:26 2013 -0400 |
| | |
| | Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net |
| | |
| | Pull in the 'net' tree to get Daniel Borkmann's flow dissector |
| | infrastructure change. |
| | |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit e052a5893b78d43bd183c6cc33bc346efe6bc6e5 |
| |Author: Wei Yongjun <yongjun_wei@trendmicro.com.cn> |
| |Date: Wed Mar 20 05:01:45 2013 +0000 |
| | |
| | net: ethernet: davinci_emac: make local function emac_poll_controller() static |
| | |
| | emac_poll_controller() was not declared. It should be static. |
| | |
| | Signed-off-by: Wei Yongjun <yongjun_wei@trendmicro.com.cn> |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit ce16294fda230c787ce5c35f61b2f80d14d70a72 |
| |Author: Lothar Waßmann <LW@KARO-electronics.de> |
| |Date: Thu Mar 21 02:20:11 2013 +0000 |
| | |
| | net: ethernet: cpsw: fix erroneous condition in error check |
| | |
| | The error check in cpsw_probe_dt() has an '&&' where an '||' is |
| | meant to be. This causes a NULL pointer dereference when incomplet DT |
| | data is passed to the driver ('phy_id' property for cpsw_emac1 |
| | missing). |
| | |
| | Signed-off-by: Lothar Waßmann <LW@KARO-electronics.de> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit ea3d1cc285bf1ae1fa81b47418cd7fd79990bb06 |
| |Merge: 2fa70df f4541d6 |
| |Author: David S. Miller <davem@davemloft.net> |
| |Date: Fri Mar 22 12:53:09 2013 -0400 |
| | |
| | Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net |
| | |
| | Pull to get the thermal netlink multicast group name fix, otherwise |
| | the assertion added in net-next to netlink to detect that kind of bug |
| | makes systems unbootable for some folks. |
| | |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit b8092861efd827deb8d84292674704ee8bf41b04 |
| |Author: Sekhar Nori <nsekhar@ti.com> |
| |Date: Sun Mar 24 23:25:46 2013 +0000 |
| | |
| | net/davinci_emac: use devres APIs |
| | |
| | Use devres APIs where possible to simplify error handling |
| | in driver probe. |
| | |
| | While at it, also rename the goto targets in error path to |
| | introduce some consistency in how they are named. |
| | |
| | Signed-off-by: Sekhar Nori <nsekhar@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit b56d6b3fca6d1214dbc9c5655f26e5d4ec04afc8 |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Wed Mar 27 04:41:59 2013 +0000 |
| | |
| | drivers: net: ethernet: cpsw: use netif_wake_queue() while restarting tx queue |
| | |
| | To restart tx queue use netif_wake_queue() intead of netif_start_queue() |
| | so that net schedule will restart transmission immediately which will |
| | increase network performance while doing huge data transfers. |
| | |
| | Reported-by: Dan Franke <dan.franke@schneider-electric.com> |
| | Suggested-by: Sriramakrishnan A G <srk@ti.com> |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Acked-by: Eric Dumazet <edumazet@google.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 7e51cde276ca820d526c6c21cf8147df595a36bf |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Wed Mar 27 04:42:00 2013 +0000 |
| | |
| | drivers: net: ethernet: davinci_emac: use netif_wake_queue() while restarting tx queue |
| | |
| | To restart tx queue use netif_wake_queue() intead of netif_start_queue() |
| | so that net schedule will restart transmission immediately which will |
| | increase network performance while doing huge data transfers. |
| | |
| | Reported-by: Dan Franke <dan.franke@schneider-electric.com> |
| | Suggested-by: Sriramakrishnan A G <srk@ti.com> |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Acked-by: Eric Dumazet <edumazet@google.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit a210576cf891e9e6d2c238eabcf5c1286b1e7526 |
| |Merge: 7d4c04f 3658f36 |
| |Author: David S. Miller <davem@davemloft.net> |
| |Date: Mon Apr 1 13:36:50 2013 -0400 |
| | |
| | Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net |
| | |
| | Conflicts: |
| | net/mac80211/sta_info.c |
| | net/wireless/core.h |
| | |
| | Two minor conflicts in wireless. Overlapping additions of extern |
| | declarations in net/wireless/core.h and a bug fix overlapping with |
| | the addition of a boolean parameter to __ieee80211_key_free(). |
| | |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 91c4166c1a01c00b8bed74f7a7defa620071de88 |
| |Author: Mugunthan V N <mugunthanvnm@ti.com> |
| |Date: Mon Apr 15 07:31:28 2013 +0000 |
| | |
| | drivers: net: ethernet: cpsw: get slave VLAN id from slave node instead of cpsw node |
| | |
| | Dual EMAC slave VLAN id must be got from slave node instead of cpsw node as |
| | VLAN id for each slave will be different. |
| | |
| | Reported-by: Mark Jackson <mpfj-list@mimc.co.uk> |
| | Signed-off-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 1e0a8b13d35510e711fdf72e9a3e30bcb2bd49fa |
| |Author: Devendra Naga <devendra.aaru@gmail.com> |
| |Date: Tue Apr 16 01:30:38 2013 +0000 |
| | |
| | tlan: cancel work at remove path |
| | |
| | the work has been scheduled from interrupt, and not been |
| | cancelled when the driver is unloaded, which doesn't remove |
| | the work item from the global workqueue. call the |
| | cancel_work_sync when the driver is removed (rmmod'ed). |
| | |
| | Cc: Sriram <srk@ti.com> |
| | Cc: Cyril Chemparathy <cyril@ti.com> |
| | Cc: Vinay Hegde <vinay.hegde@ti.com> |
| | Signed-off-by: Devendra Naga <devendra.aaru@gmail.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit f646968f8f7c624587de729115d802372b9063dd |
| |Author: Patrick McHardy <kaber@trash.net> |
| |Date: Fri Apr 19 02:04:27 2013 +0000 |
| | |
| | net: vlan: rename NETIF_F_HW_VLAN_* feature flags to NETIF_F_HW_VLAN_CTAG_* |
| | |
| | Rename the hardware VLAN acceleration features to include "CTAG" to indicate |
| | that they only support CTAGs. Follow up patches will introduce 802.1ad |
| | server provider tagging (STAGs) and require the distinction for hardware not |
| | supporting acclerating both. |
| | |
| | Signed-off-by: Patrick McHardy <kaber@trash.net> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 80d5c3689b886308247da295a228a54df49a44f6 |
| |Author: Patrick McHardy <kaber@trash.net> |
| |Date: Fri Apr 19 02:04:28 2013 +0000 |
| | |
| | net: vlan: prepare for 802.1ad VLAN filtering offload |
| | |
| | Change the rx_{add,kill}_vid callbacks to take a protocol argument in |
| | preparation of 802.1ad support. The protocol argument used so far is |
| | always htons(ETH_P_8021Q). |
| | |
| | Signed-off-by: Patrick McHardy <kaber@trash.net> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 6e0895c2ea326cc4bb11e8fa2f654628d5754c31 |
| |Merge: 55fbbe4 60d509f |
| |Author: David S. Miller <davem@davemloft.net> |
| |Date: Mon Apr 22 20:32:51 2013 -0400 |
| | |
| | Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/net |
| | |
| | Conflicts: |
| | drivers/net/ethernet/emulex/benet/be_main.c |
| | drivers/net/ethernet/intel/igb/igb_main.c |
| | drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c |
| | include/net/scm.h |
| | net/batman-adv/routing.c |
| | net/ipv4/tcp_input.c |
| | |
| | The e{uid,gid} --> {uid,gid} credentials fix conflicted with the |
| | cleanup in net-next to now pass cred structs around. |
| | |
| | The be2net driver had a bug fix in 'net' that overlapped with the VLAN |
| | interface changes by Patrick McHardy in net-next. |
| | |
| | An IGB conflict existed because in 'net' the build_skb() support was |
| | reverted, and in 'net-next' there was a comment style fix within that |
| | code. |
| | |
| | Several batman-adv conflicts were resolved by making sure that all |
| | calls to batadv_is_my_mac() are changed to have a new bat_priv first |
| | argument. |
| | |
| | Eric Dumazet's TS ECR fix in TCP in 'net' conflicted with the F-RTO |
| | rewrite in 'net-next', mostly overlapping changes. |
| | |
| | Thanks to Stephen Rothwell and Antonio Quartulli for help with several |
| | of these merge resolutions. |
| | |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 817f6d1a13754b043e1a6c1cb713763022860689 |
| |Author: Sebastian Siewior <bigeasy@linutronix.de> |
| |Date: Tue Apr 23 07:31:35 2013 +0000 |
| | |
| | net/davinci_cpdma: don't check for jiffies with interrupts |
| | |
| | __cpdma_chan_process() holds the lock with interrupts off (and its |
| | caller as well), same goes for cpdma_ctlr_start(). With interrupts off, |
| | jiffies will not make any progress and if the wait condition never gets |
| | true we wait for ever. |
| | Tgis patch adds a a simple udelay and counting down attempt. |
| | |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit aacebbf8026ecdae1b55db3912e65c6b1308f5ed |
| |Author: Sebastian Siewior <bigeasy@linutronix.de> |
| |Date: Tue Apr 23 07:31:36 2013 +0000 |
| | |
| | net/cpsw: don't continue if we miss to allocate rx skbs |
| | |
| | if during "ifconfig up" we run out of mem we continue regardless how |
| | many skbs we got. In worst case we have zero RX skbs and can't ever |
| | receive further packets since the RX skbs are never reallocated. If |
| | cpdma_chan_submit() fails we even leak the skb. |
| | This patch changes the behavior here: |
| | If we fail to allocate an skb during bring up we don't continue and |
| | report that error. Same goes for errors from cpdma_chan_submit(). |
| | While here I changed to __netdev_alloc_skb_ip_align() so GFP_KERNEL can |
| | be used. |
| | |
| | Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit fd51cf199421197d14099b4ba382301cc28e5544 |
| |Author: Sebastian Siewior <bigeasy@linutronix.de> |
| |Date: Tue Apr 23 07:31:37 2013 +0000 |
| | |
| | net/cpsw: don't rely only on netif_running() to check which device is active |
| | |
| | netif_running() reports false before the ->ndo_stop() callback is |
| | called. That means if one executes "ifconfig down" and the system |
| | receives an interrupt before the interrupt source has been disabled we |
| | hang for always for two reasons: |
| | - we never disable the interrupt source because devices claim to be |
| | already inactive and don't feel responsible. |
| | - since the ISR always reports IRQ_HANDLED the line is never deactivated |
| | because it looks like the ISR feels responsible. |
| | |
| | This patch changes the logic in the ISR a little: |
| | - If none of the status registers reports an active source (RX or TX, |
| | misc is ignored because it is not actived) we leave with IRQ_NONE. |
| | - the interrupt is deactivated |
| | - The first active network device is taken and napi is scheduled. If |
| | none are active (a small race window between ndo_down() and the |
| | interrupt the) then we leave and should not come back because the |
| | source is off. |
| | There is no need to schedule the second NAPI because both share the |
| | same dma queue. |
| | |
| | Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit aef614e13dfbdd3b9ae44ad110159f75b9029bba |
| |Author: Sebastian Siewior <bigeasy@linutronix.de> |
| |Date: Tue Apr 23 07:31:38 2013 +0000 |
| | |
| | net/davinci_cpdma: remove unused argument in cpdma_chan_submit() |
| | |
| | The gfp_mask argument is not used in cpdma_chan_submit() and always set |
| | to GFP_KERNEL even in atomic sections. This patch drops it since it is |
| | unused. |
| | |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit b4727e69b81b71c6e9696185091e8256d863f9be |
| |Author: Sebastian Siewior <bigeasy@linutronix.de> |
| |Date: Tue Apr 23 07:31:39 2013 +0000 |
| | |
| | net/cpsw: redo rx skb allocation in rx path |
| | |
| | In case that we run into OOM during the allocation of the new rx-skb we |
| | don't get one and we have one skb less than we used to have. If this |
| | continues to happen then we end up with no rx-skbs at all. |
| | This patch changes the following: |
| | - if we fail to allocate the new skb, then we treat the currently |
| | completed skb as the new one and so drop the currently received data. |
| | - instead of testing multiple times if the device is gone we rely one |
| | the status field which is set to -ENOSYS in case the channel is going |
| | down and incomplete requests are purged. |
| | cpdma_chan_stop() removes most of the packages with -ENOSYS. The |
| | currently active packet which is removed has the "tear down" bit set. |
| | So if that bit is set, we send ENOSYS as well otherwise we pass the |
| | status bits which are required to figure out which of the two possible |
| | just finished. |
| | |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 4bc21d4162366bb892dc1a4a92110c656e2622ca |
| |Author: Sebastian Siewior <bigeasy@linutronix.de> |
| |Date: Wed Apr 24 08:48:22 2013 +0000 |
| | |
| | net/ti: add MODULE_DEVICE_TABLE + MODULE_LICENSE |
| | |
| | If compiled as modules each one of these modules is missing something. |
| | With this patch the modules are loaded on demand and don't taint the |
| | kernel due to license issues. |
| | |
| | Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit d1bd9acfa3419dc9d5c32589b34a370ca6ae100e |
| |Author: Sebastian Siewior <bigeasy@linutronix.de> |
| |Date: Wed Apr 24 08:48:23 2013 +0000 |
| | |
| | net/cpsw: make sure modules remove does not leak any ressources |
| | |
| | This driver does not clean up properly after leaving. Here is a list: |
| | - Use unregister_netdev(). free_netdev() is good but not enough |
| | - Use the above also on the other ndev in case of dual mac |
| | - Free data.slave_data. The name of the strucre makes it look like |
| | it is platform_data but it is not. It is just a trick! |
| | - Free all irqs. Again: freeing one irq is good start, but freeing all |
| | of them is better. |
| | |
| | With this rmmod & modprobe of cpsw seems to work. The remaining issue |
| | is: |
| | |WARNING: at fs/sysfs/dir.c:536 sysfs_add_one+0x9c/0xd4() |
| | |sysfs: cannot create duplicate filename '/devices/ocp.2/4a100000.ethernet/4a101000.mdio' |
| | |WARNING: at lib/kobject.c:196 kobject_add_internal+0x1a4/0x1c8() |
| | |
| | comming from of_platform_populate() and I am not sure that this belongs |
| | here. |
| | |
| | Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit 6e6ceaedb5901c7ebd23e5222726dab5362938bd |
| |Author: Sebastian Siewior <bigeasy@linutronix.de> |
| |Date: Wed Apr 24 08:48:24 2013 +0000 |
| | |
| | net/cpsw: optimize the for_each_slave_macro() |
| | |
| | text data bss dec hex filename |
| | 15530 92 4 15626 3d0a cpsw.o.before |
| | 15478 92 4 15574 3cd6 cpsw.o.after |
| | |
| | 52 bytes smaller, 13 for each invocation. |
| | |
| | Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| | |
| |commit a11fbba9a7d338c4a4e4be624af0334bbf2c9a5a |
| |Author: Sebastian Siewior <bigeasy@linutronix.de> |
| |Date: Wed Apr 24 08:48:25 2013 +0000 |
| | |
| | net/cpsw: fix irq_disable() with threaded interrupts |
| | |
| | During high throughput it is likely that we receive both: an RX and TX |
| | interrupt. The normal behaviour is that once we enter the ISR the |
| | interrupts are disabled in the IRQ chip and so the ISR is invoked only |
| | once and the interrupt line is disabled once. It will be re-enabled |
| | after napi completes. |
| | With threaded interrupts on the other hand the interrupt the interrupt |
| | is disabled immediately and the ISR is marked for "later". By having TX |
| | and RX interrupt marked pending we invoke them both and disable the |
| | interrupt line twice. The napi callback is still executed once and so |
| | after it completes we remain with interrupts disabled. |
| | |
| | The initial patch simply removed the cpsw_{enable|disable}_irq() calls |
| | and it worked well on my AM335X ES1.0 (beagle bone). On ES2.0 (beagle |
| | bone black) it caused an never ending interrupt (even after the mask via |
| | cpsw_intr_disable()) according to Mugunthan V N. Since I don't have the |
| | ES2.0 and no idea what is going on this patch tracks the state of the |
| | irq_disable() call and execute it only when not yet done. |
| | The book keeping is done on the first struct since with dual_emac we can |
| | have two of those and only one interrupt line. |
| | |
| | Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| | Acked-by: Mugunthan V N <mugunthanvnm@ti.com> |
| | Signed-off-by: David S. Miller <davem@davemloft.net> |
| |
| Signed-off-by: Sebastian Andrzej Siewior <bigeasy@linutronix.de> |
| --- |
| |
| diff --git a/arch/arm/boot/dts/am33xx.dtsi b/arch/arm/boot/dts/am33xx.dtsi |
| index c2f14e8..91fe4f1 100644 |
| --- a/arch/arm/boot/dts/am33xx.dtsi |
| +++ b/arch/arm/boot/dts/am33xx.dtsi |
| @@ -349,7 +349,7 @@ |
| rx_descs = <64>; |
| mac_control = <0x20>; |
| slaves = <2>; |
| - cpts_active_slave = <0>; |
| + active_slave = <0>; |
| cpts_clock_mult = <0x80000000>; |
| cpts_clock_shift = <29>; |
| reg = <0x4a100000 0x800 |
| @@ -385,5 +385,19 @@ |
| mac-address = [ 00 00 00 00 00 00 ]; |
| }; |
| }; |
| + |
| + ocmcram: ocmcram@40300000 { |
| + compatible = "ti,am3352-ocmcram"; |
| + reg = <0x40300000 0x10000>; |
| + ti,hwmods = "ocmcram"; |
| + ti,no_idle_on_suspend; |
| + }; |
| + |
| + wkup_m3: wkup_m3@44d00000 { |
| + compatible = "ti,am3353-wkup-m3"; |
| + reg = <0x44d00000 0x4000 /* M3 UMEM */ |
| + 0x44d80000 0x2000>; /* M3 DMEM */ |
| + ti,hwmods = "wkup_m3"; |
| + }; |
| }; |
| }; |
| diff --git a/drivers/net/ethernet/ti/Kconfig b/drivers/net/ethernet/ti/Kconfig |
| index 4426151..de71b1e 100644 |
| --- a/drivers/net/ethernet/ti/Kconfig |
| +++ b/drivers/net/ethernet/ti/Kconfig |
| @@ -88,8 +88,8 @@ config TLAN |
| Please email feedback to <torben.mathiasen@compaq.com>. |
| |
| config CPMAC |
| - tristate "TI AR7 CPMAC Ethernet support (EXPERIMENTAL)" |
| - depends on EXPERIMENTAL && AR7 |
| + tristate "TI AR7 CPMAC Ethernet support" |
| + depends on AR7 |
| select PHYLIB |
| ---help--- |
| TI AR7 CPMAC Ethernet support |
| diff --git a/drivers/net/ethernet/ti/cpmac.c b/drivers/net/ethernet/ti/cpmac.c |
| index d9625f6..31bbbca 100644 |
| --- a/drivers/net/ethernet/ti/cpmac.c |
| +++ b/drivers/net/ethernet/ti/cpmac.c |
| @@ -904,10 +904,9 @@ static int cpmac_set_ringparam(struct net_device *dev, |
| static void cpmac_get_drvinfo(struct net_device *dev, |
| struct ethtool_drvinfo *info) |
| { |
| - strcpy(info->driver, "cpmac"); |
| - strcpy(info->version, CPMAC_VERSION); |
| - info->fw_version[0] = '\0'; |
| - sprintf(info->bus_info, "%s", "cpmac"); |
| + strlcpy(info->driver, "cpmac", sizeof(info->driver)); |
| + strlcpy(info->version, CPMAC_VERSION, sizeof(info->version)); |
| + snprintf(info->bus_info, sizeof(info->bus_info), "%s", "cpmac"); |
| info->regdump_len = 0; |
| } |
| |
| @@ -1173,8 +1172,8 @@ static int cpmac_probe(struct platform_device *pdev) |
| snprintf(priv->phy_name, MII_BUS_ID_SIZE, PHY_ID_FMT, |
| mdio_bus_id, phy_id); |
| |
| - priv->phy = phy_connect(dev, priv->phy_name, cpmac_adjust_link, 0, |
| - PHY_INTERFACE_MODE_MII); |
| + priv->phy = phy_connect(dev, priv->phy_name, cpmac_adjust_link, |
| + PHY_INTERFACE_MODE_MII); |
| |
| if (IS_ERR(priv->phy)) { |
| if (netif_msg_drv(priv)) |
| diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c |
| index 40aff68..4e2d224 100644 |
| --- a/drivers/net/ethernet/ti/cpsw.c |
| +++ b/drivers/net/ethernet/ti/cpsw.c |
| @@ -32,6 +32,7 @@ |
| #include <linux/of.h> |
| #include <linux/of_net.h> |
| #include <linux/of_device.h> |
| +#include <linux/if_vlan.h> |
| |
| #include <linux/platform_data/cpsw.h> |
| |
| @@ -118,6 +119,20 @@ do { \ |
| #define TX_PRIORITY_MAPPING 0x33221100 |
| #define CPDMA_TX_PRIORITY_MAP 0x76543210 |
| |
| +#define CPSW_VLAN_AWARE BIT(1) |
| +#define CPSW_ALE_VLAN_AWARE 1 |
| + |
| +#define CPSW_FIFO_NORMAL_MODE (0 << 15) |
| +#define CPSW_FIFO_DUAL_MAC_MODE (1 << 15) |
| +#define CPSW_FIFO_RATE_LIMIT_MODE (2 << 15) |
| + |
| +#define CPSW_INTPACEEN (0x3f << 16) |
| +#define CPSW_INTPRESCALE_MASK (0x7FF << 0) |
| +#define CPSW_CMINTMAX_CNT 63 |
| +#define CPSW_CMINTMIN_CNT 2 |
| +#define CPSW_CMINTMAX_INTVL (1000 / CPSW_CMINTMIN_CNT) |
| +#define CPSW_CMINTMIN_INTVL ((1000 / CPSW_CMINTMAX_CNT) + 1) |
| + |
| #define cpsw_enable_irq(priv) \ |
| do { \ |
| u32 i; \ |
| @@ -131,6 +146,10 @@ do { \ |
| disable_irq_nosync(priv->irqs_table[i]); \ |
| } while (0); |
| |
| +#define cpsw_slave_index(priv) \ |
| + ((priv->data.dual_emac) ? priv->emac_port : \ |
| + priv->data.active_slave) |
| + |
| static int debug_level; |
| module_param(debug_level, int, 0); |
| MODULE_PARM_DESC(debug_level, "cpsw debug level (NETIF_MSG bits)"); |
| @@ -152,6 +171,15 @@ struct cpsw_wr_regs { |
| u32 rx_en; |
| u32 tx_en; |
| u32 misc_en; |
| + u32 mem_allign1[8]; |
| + u32 rx_thresh_stat; |
| + u32 rx_stat; |
| + u32 tx_stat; |
| + u32 misc_stat; |
| + u32 mem_allign2[8]; |
| + u32 rx_imax; |
| + u32 tx_imax; |
| + |
| }; |
| |
| struct cpsw_ss_regs { |
| @@ -250,7 +278,7 @@ struct cpsw_ss_regs { |
| struct cpsw_host_regs { |
| u32 max_blks; |
| u32 blk_cnt; |
| - u32 flow_thresh; |
| + u32 tx_in_ctl; |
| u32 port_vlan; |
| u32 tx_pri_map; |
| u32 cpdma_tx_pri_map; |
| @@ -277,6 +305,9 @@ struct cpsw_slave { |
| u32 mac_control; |
| struct cpsw_slave_data *data; |
| struct phy_device *phy; |
| + struct net_device *ndev; |
| + u32 port_vlan; |
| + u32 open_stat; |
| }; |
| |
| static inline u32 slave_read(struct cpsw_slave *slave, u32 offset) |
| @@ -303,6 +334,8 @@ struct cpsw_priv { |
| struct cpsw_host_regs __iomem *host_port_regs; |
| u32 msg_enable; |
| u32 version; |
| + u32 coal_intvl; |
| + u32 bus_freq_mhz; |
| struct net_device_stats stats; |
| int rx_packet_max; |
| int host_port; |
| @@ -315,17 +348,69 @@ struct cpsw_priv { |
| /* snapshot of IRQ numbers */ |
| u32 irqs_table[4]; |
| u32 num_irqs; |
| - struct cpts cpts; |
| + bool irq_enabled; |
| + struct cpts *cpts; |
| + u32 emac_port; |
| }; |
| |
| #define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi) |
| -#define for_each_slave(priv, func, arg...) \ |
| - do { \ |
| - int idx; \ |
| - for (idx = 0; idx < (priv)->data.slaves; idx++) \ |
| - (func)((priv)->slaves + idx, ##arg); \ |
| +#define for_each_slave(priv, func, arg...) \ |
| + do { \ |
| + struct cpsw_slave *slave; \ |
| + int n; \ |
| + if (priv->data.dual_emac) \ |
| + (func)((priv)->slaves + priv->emac_port, ##arg);\ |
| + else \ |
| + for (n = (priv)->data.slaves, \ |
| + slave = (priv)->slaves; \ |
| + n; n--) \ |
| + (func)(slave++, ##arg); \ |
| + } while (0) |
| +#define cpsw_get_slave_ndev(priv, __slave_no__) \ |
| + (priv->slaves[__slave_no__].ndev) |
| +#define cpsw_get_slave_priv(priv, __slave_no__) \ |
| + ((priv->slaves[__slave_no__].ndev) ? \ |
| + netdev_priv(priv->slaves[__slave_no__].ndev) : NULL) \ |
| + |
| +#define cpsw_dual_emac_src_port_detect(status, priv, ndev, skb) \ |
| + do { \ |
| + if (!priv->data.dual_emac) \ |
| + break; \ |
| + if (CPDMA_RX_SOURCE_PORT(status) == 1) { \ |
| + ndev = cpsw_get_slave_ndev(priv, 0); \ |
| + priv = netdev_priv(ndev); \ |
| + skb->dev = ndev; \ |
| + } else if (CPDMA_RX_SOURCE_PORT(status) == 2) { \ |
| + ndev = cpsw_get_slave_ndev(priv, 1); \ |
| + priv = netdev_priv(ndev); \ |
| + skb->dev = ndev; \ |
| + } \ |
| + } while (0) |
| +#define cpsw_add_mcast(priv, addr) \ |
| + do { \ |
| + if (priv->data.dual_emac) { \ |
| + struct cpsw_slave *slave = priv->slaves + \ |
| + priv->emac_port; \ |
| + int slave_port = cpsw_get_slave_port(priv, \ |
| + slave->slave_num); \ |
| + cpsw_ale_add_mcast(priv->ale, addr, \ |
| + 1 << slave_port | 1 << priv->host_port, \ |
| + ALE_VLAN, slave->port_vlan, 0); \ |
| + } else { \ |
| + cpsw_ale_add_mcast(priv->ale, addr, \ |
| + ALE_ALL_PORTS << priv->host_port, \ |
| + 0, 0, 0); \ |
| + } \ |
| } while (0) |
| |
| +static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) |
| +{ |
| + if (priv->host_port == 0) |
| + return slave_num + 1; |
| + else |
| + return slave_num; |
| +} |
| + |
| static void cpsw_ndo_set_rx_mode(struct net_device *ndev) |
| { |
| struct cpsw_priv *priv = netdev_priv(ndev); |
| @@ -344,8 +429,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev) |
| |
| /* program multicast address list into ALE register */ |
| netdev_for_each_mc_addr(ha, ndev) { |
| - cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr, |
| - ALE_ALL_PORTS << priv->host_port, 0, 0); |
| + cpsw_add_mcast(priv, (u8 *)ha->addr); |
| } |
| } |
| } |
| @@ -374,9 +458,12 @@ void cpsw_tx_handler(void *token, int len, int status) |
| struct net_device *ndev = skb->dev; |
| struct cpsw_priv *priv = netdev_priv(ndev); |
| |
| + /* Check whether the queue is stopped due to stalled tx dma, if the |
| + * queue is stopped then start the queue as we have free desc for tx |
| + */ |
| if (unlikely(netif_queue_stopped(ndev))) |
| - netif_start_queue(ndev); |
| - cpts_tx_timestamp(&priv->cpts, skb); |
| + netif_wake_queue(ndev); |
| + cpts_tx_timestamp(priv->cpts, skb); |
| priv->stats.tx_packets++; |
| priv->stats.tx_bytes += len; |
| dev_kfree_skb_any(skb); |
| @@ -385,61 +472,69 @@ void cpsw_tx_handler(void *token, int len, int status) |
| void cpsw_rx_handler(void *token, int len, int status) |
| { |
| struct sk_buff *skb = token; |
| + struct sk_buff *new_skb; |
| struct net_device *ndev = skb->dev; |
| struct cpsw_priv *priv = netdev_priv(ndev); |
| int ret = 0; |
| |
| - /* free and bail if we are shutting down */ |
| - if (unlikely(!netif_running(ndev)) || |
| - unlikely(!netif_carrier_ok(ndev))) { |
| + cpsw_dual_emac_src_port_detect(status, priv, ndev, skb); |
| + |
| + if (unlikely(status < 0)) { |
| + /* the interface is going down, skbs are purged */ |
| dev_kfree_skb_any(skb); |
| return; |
| } |
| - if (likely(status >= 0)) { |
| + |
| + new_skb = netdev_alloc_skb_ip_align(ndev, priv->rx_packet_max); |
| + if (new_skb) { |
| skb_put(skb, len); |
| - cpts_rx_timestamp(&priv->cpts, skb); |
| + cpts_rx_timestamp(priv->cpts, skb); |
| skb->protocol = eth_type_trans(skb, ndev); |
| netif_receive_skb(skb); |
| priv->stats.rx_bytes += len; |
| priv->stats.rx_packets++; |
| - skb = NULL; |
| - } |
| - |
| - if (unlikely(!netif_running(ndev))) { |
| - if (skb) |
| - dev_kfree_skb_any(skb); |
| - return; |
| + } else { |
| + priv->stats.rx_dropped++; |
| + new_skb = skb; |
| } |
| |
| - if (likely(!skb)) { |
| - skb = netdev_alloc_skb_ip_align(ndev, priv->rx_packet_max); |
| - if (WARN_ON(!skb)) |
| - return; |
| - |
| - ret = cpdma_chan_submit(priv->rxch, skb, skb->data, |
| - skb_tailroom(skb), GFP_KERNEL); |
| - } |
| - WARN_ON(ret < 0); |
| + ret = cpdma_chan_submit(priv->rxch, new_skb, new_skb->data, |
| + skb_tailroom(new_skb), 0); |
| + if (WARN_ON(ret < 0)) |
| + dev_kfree_skb_any(new_skb); |
| } |
| |
| static irqreturn_t cpsw_interrupt(int irq, void *dev_id) |
| { |
| struct cpsw_priv *priv = dev_id; |
| + u32 rx, tx, rx_thresh; |
| |
| - if (likely(netif_running(priv->ndev))) { |
| - cpsw_intr_disable(priv); |
| + rx_thresh = __raw_readl(&priv->wr_regs->rx_thresh_stat); |
| + rx = __raw_readl(&priv->wr_regs->rx_stat); |
| + tx = __raw_readl(&priv->wr_regs->tx_stat); |
| + if (!rx_thresh && !rx && !tx) |
| + return IRQ_NONE; |
| + |
| + cpsw_intr_disable(priv); |
| + if (priv->irq_enabled == true) { |
| cpsw_disable_irq(priv); |
| + priv->irq_enabled = false; |
| + } |
| + |
| + if (netif_running(priv->ndev)) { |
| napi_schedule(&priv->napi); |
| + return IRQ_HANDLED; |
| } |
| - return IRQ_HANDLED; |
| -} |
| |
| -static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num) |
| -{ |
| - if (priv->host_port == 0) |
| - return slave_num + 1; |
| - else |
| - return slave_num; |
| + priv = cpsw_get_slave_priv(priv, 1); |
| + if (!priv) |
| + return IRQ_NONE; |
| + |
| + if (netif_running(priv->ndev)) { |
| + napi_schedule(&priv->napi); |
| + return IRQ_HANDLED; |
| + } |
| + return IRQ_NONE; |
| } |
| |
| static int cpsw_poll(struct napi_struct *napi, int budget) |
| @@ -448,19 +543,27 @@ static int cpsw_poll(struct napi_struct *napi, int budget) |
| int num_tx, num_rx; |
| |
| num_tx = cpdma_chan_process(priv->txch, 128); |
| - num_rx = cpdma_chan_process(priv->rxch, budget); |
| - |
| - if (num_rx || num_tx) |
| - cpsw_dbg(priv, intr, "poll %d rx, %d tx pkts\n", |
| - num_rx, num_tx); |
| + if (num_tx) |
| + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); |
| |
| + num_rx = cpdma_chan_process(priv->rxch, budget); |
| if (num_rx < budget) { |
| + struct cpsw_priv *prim_cpsw; |
| + |
| napi_complete(napi); |
| cpsw_intr_enable(priv); |
| - cpdma_ctlr_eoi(priv->dma); |
| - cpsw_enable_irq(priv); |
| + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); |
| + prim_cpsw = cpsw_get_slave_priv(priv, 0); |
| + if (prim_cpsw->irq_enabled == false) { |
| + cpsw_enable_irq(priv); |
| + prim_cpsw->irq_enabled = true; |
| + } |
| } |
| |
| + if (num_rx || num_tx) |
| + cpsw_dbg(priv, intr, "poll %d rx, %d tx pkts\n", |
| + num_rx, num_tx); |
| + |
| return num_rx; |
| } |
| |
| @@ -548,6 +651,77 @@ static void cpsw_adjust_link(struct net_device *ndev) |
| } |
| } |
| |
| +static int cpsw_get_coalesce(struct net_device *ndev, |
| + struct ethtool_coalesce *coal) |
| +{ |
| + struct cpsw_priv *priv = netdev_priv(ndev); |
| + |
| + coal->rx_coalesce_usecs = priv->coal_intvl; |
| + return 0; |
| +} |
| + |
| +static int cpsw_set_coalesce(struct net_device *ndev, |
| + struct ethtool_coalesce *coal) |
| +{ |
| + struct cpsw_priv *priv = netdev_priv(ndev); |
| + u32 int_ctrl; |
| + u32 num_interrupts = 0; |
| + u32 prescale = 0; |
| + u32 addnl_dvdr = 1; |
| + u32 coal_intvl = 0; |
| + |
| + if (!coal->rx_coalesce_usecs) |
| + return -EINVAL; |
| + |
| + coal_intvl = coal->rx_coalesce_usecs; |
| + |
| + int_ctrl = readl(&priv->wr_regs->int_control); |
| + prescale = priv->bus_freq_mhz * 4; |
| + |
| + if (coal_intvl < CPSW_CMINTMIN_INTVL) |
| + coal_intvl = CPSW_CMINTMIN_INTVL; |
| + |
| + if (coal_intvl > CPSW_CMINTMAX_INTVL) { |
| + /* Interrupt pacer works with 4us Pulse, we can |
| + * throttle further by dilating the 4us pulse. |
| + */ |
| + addnl_dvdr = CPSW_INTPRESCALE_MASK / prescale; |
| + |
| + if (addnl_dvdr > 1) { |
| + prescale *= addnl_dvdr; |
| + if (coal_intvl > (CPSW_CMINTMAX_INTVL * addnl_dvdr)) |
| + coal_intvl = (CPSW_CMINTMAX_INTVL |
| + * addnl_dvdr); |
| + } else { |
| + addnl_dvdr = 1; |
| + coal_intvl = CPSW_CMINTMAX_INTVL; |
| + } |
| + } |
| + |
| + num_interrupts = (1000 * addnl_dvdr) / coal_intvl; |
| + writel(num_interrupts, &priv->wr_regs->rx_imax); |
| + writel(num_interrupts, &priv->wr_regs->tx_imax); |
| + |
| + int_ctrl |= CPSW_INTPACEEN; |
| + int_ctrl &= (~CPSW_INTPRESCALE_MASK); |
| + int_ctrl |= (prescale & CPSW_INTPRESCALE_MASK); |
| + writel(int_ctrl, &priv->wr_regs->int_control); |
| + |
| + cpsw_notice(priv, timer, "Set coalesce to %d usecs.\n", coal_intvl); |
| + if (priv->data.dual_emac) { |
| + int i; |
| + |
| + for (i = 0; i < priv->data.slaves; i++) { |
| + priv = netdev_priv(priv->slaves[i].ndev); |
| + priv->coal_intvl = coal_intvl; |
| + } |
| + } else { |
| + priv->coal_intvl = coal_intvl; |
| + } |
| + |
| + return 0; |
| +} |
| + |
| static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val) |
| { |
| static char *leader = "........................................"; |
| @@ -559,6 +733,54 @@ static inline int __show_stat(char *buf, int maxlen, const char *name, u32 val) |
| leader + strlen(name), val); |
| } |
| |
| +static int cpsw_common_res_usage_state(struct cpsw_priv *priv) |
| +{ |
| + u32 i; |
| + u32 usage_count = 0; |
| + |
| + if (!priv->data.dual_emac) |
| + return 0; |
| + |
| + for (i = 0; i < priv->data.slaves; i++) |
| + if (priv->slaves[i].open_stat) |
| + usage_count++; |
| + |
| + return usage_count; |
| +} |
| + |
| +static inline int cpsw_tx_packet_submit(struct net_device *ndev, |
| + struct cpsw_priv *priv, struct sk_buff *skb) |
| +{ |
| + if (!priv->data.dual_emac) |
| + return cpdma_chan_submit(priv->txch, skb, skb->data, |
| + skb->len, 0); |
| + |
| + if (ndev == cpsw_get_slave_ndev(priv, 0)) |
| + return cpdma_chan_submit(priv->txch, skb, skb->data, |
| + skb->len, 1); |
| + else |
| + return cpdma_chan_submit(priv->txch, skb, skb->data, |
| + skb->len, 2); |
| +} |
| + |
| +static inline void cpsw_add_dual_emac_def_ale_entries( |
| + struct cpsw_priv *priv, struct cpsw_slave *slave, |
| + u32 slave_port) |
| +{ |
| + u32 port_mask = 1 << slave_port | 1 << priv->host_port; |
| + |
| + if (priv->version == CPSW_VERSION_1) |
| + slave_write(slave, slave->port_vlan, CPSW1_PORT_VLAN); |
| + else |
| + slave_write(slave, slave->port_vlan, CPSW2_PORT_VLAN); |
| + cpsw_ale_add_vlan(priv->ale, slave->port_vlan, port_mask, |
| + port_mask, port_mask, 0); |
| + cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, |
| + port_mask, ALE_VLAN, slave->port_vlan, 0); |
| + cpsw_ale_add_ucast(priv->ale, priv->mac_addr, |
| + priv->host_port, ALE_VLAN, slave->port_vlan); |
| +} |
| + |
| static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) |
| { |
| char name[32]; |
| @@ -588,11 +810,14 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) |
| |
| slave_port = cpsw_get_slave_port(priv, slave->slave_num); |
| |
| - cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, |
| - 1 << slave_port, 0, ALE_MCAST_FWD_2); |
| + if (priv->data.dual_emac) |
| + cpsw_add_dual_emac_def_ale_entries(priv, slave, slave_port); |
| + else |
| + cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, |
| + 1 << slave_port, 0, 0, ALE_MCAST_FWD_2); |
| |
| slave->phy = phy_connect(priv->ndev, slave->data->phy_id, |
| - &cpsw_adjust_link, 0, slave->data->phy_if); |
| + &cpsw_adjust_link, slave->data->phy_if); |
| if (IS_ERR(slave->phy)) { |
| dev_err(priv->dev, "phy %s not found on slave %d\n", |
| slave->data->phy_id, slave->slave_num); |
| @@ -604,14 +829,44 @@ static void cpsw_slave_open(struct cpsw_slave *slave, struct cpsw_priv *priv) |
| } |
| } |
| |
| +static inline void cpsw_add_default_vlan(struct cpsw_priv *priv) |
| +{ |
| + const int vlan = priv->data.default_vlan; |
| + const int port = priv->host_port; |
| + u32 reg; |
| + int i; |
| + |
| + reg = (priv->version == CPSW_VERSION_1) ? CPSW1_PORT_VLAN : |
| + CPSW2_PORT_VLAN; |
| + |
| + writel(vlan, &priv->host_port_regs->port_vlan); |
| + |
| + for (i = 0; i < priv->data.slaves; i++) |
| + slave_write(priv->slaves + i, vlan, reg); |
| + |
| + cpsw_ale_add_vlan(priv->ale, vlan, ALE_ALL_PORTS << port, |
| + ALE_ALL_PORTS << port, ALE_ALL_PORTS << port, |
| + (ALE_PORT_1 | ALE_PORT_2) << port); |
| +} |
| + |
| static void cpsw_init_host_port(struct cpsw_priv *priv) |
| { |
| + u32 control_reg; |
| + u32 fifo_mode; |
| + |
| /* soft reset the controller and initialize ale */ |
| soft_reset("cpsw", &priv->regs->soft_reset); |
| cpsw_ale_start(priv->ale); |
| |
| /* switch to vlan unaware mode */ |
| - cpsw_ale_control_set(priv->ale, 0, ALE_VLAN_AWARE, 0); |
| + cpsw_ale_control_set(priv->ale, priv->host_port, ALE_VLAN_AWARE, |
| + CPSW_ALE_VLAN_AWARE); |
| + control_reg = readl(&priv->regs->control); |
| + control_reg |= CPSW_VLAN_AWARE; |
| + writel(control_reg, &priv->regs->control); |
| + fifo_mode = (priv->data.dual_emac) ? CPSW_FIFO_DUAL_MAC_MODE : |
| + CPSW_FIFO_NORMAL_MODE; |
| + writel(fifo_mode, &priv->host_port_regs->tx_in_ctl); |
| |
| /* setup host port priority mapping */ |
| __raw_writel(CPDMA_TX_PRIORITY_MAP, |
| @@ -621,18 +876,32 @@ static void cpsw_init_host_port(struct cpsw_priv *priv) |
| cpsw_ale_control_set(priv->ale, priv->host_port, |
| ALE_PORT_STATE, ALE_PORT_STATE_FORWARD); |
| |
| - cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, 0); |
| - cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, |
| - 1 << priv->host_port, 0, ALE_MCAST_FWD_2); |
| + if (!priv->data.dual_emac) { |
| + cpsw_ale_add_ucast(priv->ale, priv->mac_addr, priv->host_port, |
| + 0, 0); |
| + cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, |
| + 1 << priv->host_port, 0, 0, ALE_MCAST_FWD_2); |
| + } |
| +} |
| + |
| +static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv) |
| +{ |
| + if (!slave->phy) |
| + return; |
| + phy_stop(slave->phy); |
| + phy_disconnect(slave->phy); |
| + slave->phy = NULL; |
| } |
| |
| static int cpsw_ndo_open(struct net_device *ndev) |
| { |
| struct cpsw_priv *priv = netdev_priv(ndev); |
| + struct cpsw_priv *prim_cpsw; |
| int i, ret; |
| u32 reg; |
| |
| - cpsw_intr_disable(priv); |
| + if (!cpsw_common_res_usage_state(priv)) |
| + cpsw_intr_disable(priv); |
| netif_carrier_off(ndev); |
| |
| pm_runtime_get_sync(&priv->pdev->dev); |
| @@ -644,53 +913,81 @@ static int cpsw_ndo_open(struct net_device *ndev) |
| CPSW_RTL_VERSION(reg)); |
| |
| /* initialize host and slave ports */ |
| - cpsw_init_host_port(priv); |
| + if (!cpsw_common_res_usage_state(priv)) |
| + cpsw_init_host_port(priv); |
| for_each_slave(priv, cpsw_slave_open, priv); |
| |
| - /* setup tx dma to fixed prio and zero offset */ |
| - cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1); |
| - cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0); |
| - |
| - /* disable priority elevation and enable statistics on all ports */ |
| - __raw_writel(0, &priv->regs->ptype); |
| - |
| - /* enable statistics collection only on the host port */ |
| - __raw_writel(0x7, &priv->regs->stat_port_en); |
| + /* Add default VLAN */ |
| + if (!priv->data.dual_emac) |
| + cpsw_add_default_vlan(priv); |
| + |
| + if (!cpsw_common_res_usage_state(priv)) { |
| + /* setup tx dma to fixed prio and zero offset */ |
| + cpdma_control_set(priv->dma, CPDMA_TX_PRIO_FIXED, 1); |
| + cpdma_control_set(priv->dma, CPDMA_RX_BUFFER_OFFSET, 0); |
| + |
| + /* disable priority elevation */ |
| + __raw_writel(0, &priv->regs->ptype); |
| + |
| + /* enable statistics collection only on all ports */ |
| + __raw_writel(0x7, &priv->regs->stat_port_en); |
| + |
| + if (WARN_ON(!priv->data.rx_descs)) |
| + priv->data.rx_descs = 128; |
| + |
| + for (i = 0; i < priv->data.rx_descs; i++) { |
| + struct sk_buff *skb; |
| + |
| + ret = -ENOMEM; |
| + skb = __netdev_alloc_skb_ip_align(priv->ndev, |
| + priv->rx_packet_max, GFP_KERNEL); |
| + if (!skb) |
| + goto err_cleanup; |
| + ret = cpdma_chan_submit(priv->rxch, skb, skb->data, |
| + skb_tailroom(skb), 0); |
| + if (ret < 0) { |
| + kfree_skb(skb); |
| + goto err_cleanup; |
| + } |
| + } |
| + /* continue even if we didn't manage to submit all |
| + * receive descs |
| + */ |
| + cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i); |
| + } |
| |
| - if (WARN_ON(!priv->data.rx_descs)) |
| - priv->data.rx_descs = 128; |
| + /* Enable Interrupt pacing if configured */ |
| + if (priv->coal_intvl != 0) { |
| + struct ethtool_coalesce coal; |
| |
| - for (i = 0; i < priv->data.rx_descs; i++) { |
| - struct sk_buff *skb; |
| + coal.rx_coalesce_usecs = (priv->coal_intvl << 4); |
| + cpsw_set_coalesce(ndev, &coal); |
| + } |
| |
| - ret = -ENOMEM; |
| - skb = netdev_alloc_skb_ip_align(priv->ndev, |
| - priv->rx_packet_max); |
| - if (!skb) |
| - break; |
| - ret = cpdma_chan_submit(priv->rxch, skb, skb->data, |
| - skb_tailroom(skb), GFP_KERNEL); |
| - if (WARN_ON(ret < 0)) |
| - break; |
| + prim_cpsw = cpsw_get_slave_priv(priv, 0); |
| + if (prim_cpsw->irq_enabled == false) { |
| + if ((priv == prim_cpsw) || !netif_running(prim_cpsw->ndev)) { |
| + prim_cpsw->irq_enabled = true; |
| + cpsw_enable_irq(prim_cpsw); |
| + } |
| } |
| - /* continue even if we didn't manage to submit all receive descs */ |
| - cpsw_info(priv, ifup, "submitted %d rx descriptors\n", i); |
| |
| cpdma_ctlr_start(priv->dma); |
| cpsw_intr_enable(priv); |
| napi_enable(&priv->napi); |
| - cpdma_ctlr_eoi(priv->dma); |
| + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); |
| + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); |
| |
| + if (priv->data.dual_emac) |
| + priv->slaves[priv->emac_port].open_stat = true; |
| return 0; |
| -} |
| |
| -static void cpsw_slave_stop(struct cpsw_slave *slave, struct cpsw_priv *priv) |
| -{ |
| - if (!slave->phy) |
| - return; |
| - phy_stop(slave->phy); |
| - phy_disconnect(slave->phy); |
| - slave->phy = NULL; |
| +err_cleanup: |
| + cpdma_ctlr_stop(priv->dma); |
| + for_each_slave(priv, cpsw_slave_stop, priv); |
| + pm_runtime_put_sync(&priv->pdev->dev); |
| + netif_carrier_off(priv->ndev); |
| + return ret; |
| } |
| |
| static int cpsw_ndo_stop(struct net_device *ndev) |
| @@ -701,12 +998,17 @@ static int cpsw_ndo_stop(struct net_device *ndev) |
| netif_stop_queue(priv->ndev); |
| napi_disable(&priv->napi); |
| netif_carrier_off(priv->ndev); |
| - cpsw_intr_disable(priv); |
| - cpdma_ctlr_int_ctrl(priv->dma, false); |
| - cpdma_ctlr_stop(priv->dma); |
| - cpsw_ale_stop(priv->ale); |
| + |
| + if (cpsw_common_res_usage_state(priv) <= 1) { |
| + cpsw_intr_disable(priv); |
| + cpdma_ctlr_int_ctrl(priv->dma, false); |
| + cpdma_ctlr_stop(priv->dma); |
| + cpsw_ale_stop(priv->ale); |
| + } |
| for_each_slave(priv, cpsw_slave_stop, priv); |
| pm_runtime_put_sync(&priv->pdev->dev); |
| + if (priv->data.dual_emac) |
| + priv->slaves[priv->emac_port].open_stat = false; |
| return 0; |
| } |
| |
| @@ -724,18 +1026,24 @@ static netdev_tx_t cpsw_ndo_start_xmit(struct sk_buff *skb, |
| return NETDEV_TX_OK; |
| } |
| |
| - if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && priv->cpts.tx_enable) |
| + if (skb_shinfo(skb)->tx_flags & SKBTX_HW_TSTAMP && |
| + priv->cpts->tx_enable) |
| skb_shinfo(skb)->tx_flags |= SKBTX_IN_PROGRESS; |
| |
| skb_tx_timestamp(skb); |
| |
| - ret = cpdma_chan_submit(priv->txch, skb, skb->data, |
| - skb->len, GFP_KERNEL); |
| + ret = cpsw_tx_packet_submit(ndev, priv, skb); |
| if (unlikely(ret != 0)) { |
| cpsw_err(priv, tx_err, "desc submit failed\n"); |
| goto fail; |
| } |
| |
| + /* If there is no more tx desc left free then we need to |
| + * tell the kernel to stop sending us tx frames. |
| + */ |
| + if (unlikely(!cpdma_check_free_tx_desc(priv->txch))) |
| + netif_stop_queue(ndev); |
| + |
| return NETDEV_TX_OK; |
| fail: |
| priv->stats.tx_dropped++; |
| @@ -770,10 +1078,10 @@ static void cpsw_ndo_change_rx_flags(struct net_device *ndev, int flags) |
| |
| static void cpsw_hwtstamp_v1(struct cpsw_priv *priv) |
| { |
| - struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave]; |
| + struct cpsw_slave *slave = &priv->slaves[priv->data.active_slave]; |
| u32 ts_en, seq_id; |
| |
| - if (!priv->cpts.tx_enable && !priv->cpts.rx_enable) { |
| + if (!priv->cpts->tx_enable && !priv->cpts->rx_enable) { |
| slave_write(slave, 0, CPSW1_TS_CTL); |
| return; |
| } |
| @@ -781,10 +1089,10 @@ static void cpsw_hwtstamp_v1(struct cpsw_priv *priv) |
| seq_id = (30 << CPSW_V1_SEQ_ID_OFS_SHIFT) | ETH_P_1588; |
| ts_en = EVENT_MSG_BITS << CPSW_V1_MSG_TYPE_OFS; |
| |
| - if (priv->cpts.tx_enable) |
| + if (priv->cpts->tx_enable) |
| ts_en |= CPSW_V1_TS_TX_EN; |
| |
| - if (priv->cpts.rx_enable) |
| + if (priv->cpts->rx_enable) |
| ts_en |= CPSW_V1_TS_RX_EN; |
| |
| slave_write(slave, ts_en, CPSW1_TS_CTL); |
| @@ -793,16 +1101,21 @@ static void cpsw_hwtstamp_v1(struct cpsw_priv *priv) |
| |
| static void cpsw_hwtstamp_v2(struct cpsw_priv *priv) |
| { |
| - struct cpsw_slave *slave = &priv->slaves[priv->data.cpts_active_slave]; |
| + struct cpsw_slave *slave; |
| u32 ctrl, mtype; |
| |
| + if (priv->data.dual_emac) |
| + slave = &priv->slaves[priv->emac_port]; |
| + else |
| + slave = &priv->slaves[priv->data.active_slave]; |
| + |
| ctrl = slave_read(slave, CPSW2_CONTROL); |
| ctrl &= ~CTRL_ALL_TS_MASK; |
| |
| - if (priv->cpts.tx_enable) |
| + if (priv->cpts->tx_enable) |
| ctrl |= CTRL_TX_TS_BITS; |
| |
| - if (priv->cpts.rx_enable) |
| + if (priv->cpts->rx_enable) |
| ctrl |= CTRL_RX_TS_BITS; |
| |
| mtype = (30 << TS_SEQ_ID_OFFSET_SHIFT) | EVENT_MSG_BITS; |
| @@ -815,7 +1128,7 @@ static void cpsw_hwtstamp_v2(struct cpsw_priv *priv) |
| static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) |
| { |
| struct cpsw_priv *priv = netdev_priv(dev); |
| - struct cpts *cpts = &priv->cpts; |
| + struct cpts *cpts = priv->cpts; |
| struct hwtstamp_config cfg; |
| |
| if (copy_from_user(&cfg, ifr->ifr_data, sizeof(cfg))) |
| @@ -879,14 +1192,26 @@ static int cpsw_hwtstamp_ioctl(struct net_device *dev, struct ifreq *ifr) |
| |
| static int cpsw_ndo_ioctl(struct net_device *dev, struct ifreq *req, int cmd) |
| { |
| + struct cpsw_priv *priv = netdev_priv(dev); |
| + struct mii_ioctl_data *data = if_mii(req); |
| + int slave_no = cpsw_slave_index(priv); |
| + |
| if (!netif_running(dev)) |
| return -EINVAL; |
| |
| + switch (cmd) { |
| #ifdef CONFIG_TI_CPTS |
| - if (cmd == SIOCSHWTSTAMP) |
| + case SIOCSHWTSTAMP: |
| return cpsw_hwtstamp_ioctl(dev, req); |
| #endif |
| - return -ENOTSUPP; |
| + case SIOCGMIIPHY: |
| + data->phy_id = priv->slaves[slave_no].phy->addr; |
| + break; |
| + default: |
| + return -ENOTSUPP; |
| + } |
| + |
| + return 0; |
| } |
| |
| static void cpsw_ndo_tx_timeout(struct net_device *ndev) |
| @@ -901,7 +1226,9 @@ static void cpsw_ndo_tx_timeout(struct net_device *ndev) |
| cpdma_chan_start(priv->txch); |
| cpdma_ctlr_int_ctrl(priv->dma, true); |
| cpsw_intr_enable(priv); |
| - cpdma_ctlr_eoi(priv->dma); |
| + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); |
| + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); |
| + |
| } |
| |
| static struct net_device_stats *cpsw_ndo_get_stats(struct net_device *ndev) |
| @@ -920,10 +1247,79 @@ static void cpsw_ndo_poll_controller(struct net_device *ndev) |
| cpsw_interrupt(ndev->irq, priv); |
| cpdma_ctlr_int_ctrl(priv->dma, true); |
| cpsw_intr_enable(priv); |
| - cpdma_ctlr_eoi(priv->dma); |
| + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_RX); |
| + cpdma_ctlr_eoi(priv->dma, CPDMA_EOI_TX); |
| + |
| } |
| #endif |
| |
| +static inline int cpsw_add_vlan_ale_entry(struct cpsw_priv *priv, |
| + unsigned short vid) |
| +{ |
| + int ret; |
| + |
| + ret = cpsw_ale_add_vlan(priv->ale, vid, |
| + ALE_ALL_PORTS << priv->host_port, |
| + 0, ALE_ALL_PORTS << priv->host_port, |
| + (ALE_PORT_1 | ALE_PORT_2) << priv->host_port); |
| + if (ret != 0) |
| + return ret; |
| + |
| + ret = cpsw_ale_add_ucast(priv->ale, priv->mac_addr, |
| + priv->host_port, ALE_VLAN, vid); |
| + if (ret != 0) |
| + goto clean_vid; |
| + |
| + ret = cpsw_ale_add_mcast(priv->ale, priv->ndev->broadcast, |
| + ALE_ALL_PORTS << priv->host_port, |
| + ALE_VLAN, vid, 0); |
| + if (ret != 0) |
| + goto clean_vlan_ucast; |
| + return 0; |
| + |
| +clean_vlan_ucast: |
| + cpsw_ale_del_ucast(priv->ale, priv->mac_addr, |
| + priv->host_port, ALE_VLAN, vid); |
| +clean_vid: |
| + cpsw_ale_del_vlan(priv->ale, vid, 0); |
| + return ret; |
| +} |
| + |
| +static int cpsw_ndo_vlan_rx_add_vid(struct net_device *ndev, |
| + __be16 proto, u16 vid) |
| +{ |
| + struct cpsw_priv *priv = netdev_priv(ndev); |
| + |
| + if (vid == priv->data.default_vlan) |
| + return 0; |
| + |
| + dev_info(priv->dev, "Adding vlanid %d to vlan filter\n", vid); |
| + return cpsw_add_vlan_ale_entry(priv, vid); |
| +} |
| + |
| +static int cpsw_ndo_vlan_rx_kill_vid(struct net_device *ndev, |
| + __be16 proto, u16 vid) |
| +{ |
| + struct cpsw_priv *priv = netdev_priv(ndev); |
| + int ret; |
| + |
| + if (vid == priv->data.default_vlan) |
| + return 0; |
| + |
| + dev_info(priv->dev, "removing vlanid %d from vlan filter\n", vid); |
| + ret = cpsw_ale_del_vlan(priv->ale, vid, 0); |
| + if (ret != 0) |
| + return ret; |
| + |
| + ret = cpsw_ale_del_ucast(priv->ale, priv->mac_addr, |
| + priv->host_port, ALE_VLAN, vid); |
| + if (ret != 0) |
| + return ret; |
| + |
| + return cpsw_ale_del_mcast(priv->ale, priv->ndev->broadcast, |
| + 0, ALE_VLAN, vid); |
| +} |
| + |
| static const struct net_device_ops cpsw_netdev_ops = { |
| .ndo_open = cpsw_ndo_open, |
| .ndo_stop = cpsw_ndo_stop, |
| @@ -938,15 +1334,18 @@ static const struct net_device_ops cpsw_netdev_ops = { |
| #ifdef CONFIG_NET_POLL_CONTROLLER |
| .ndo_poll_controller = cpsw_ndo_poll_controller, |
| #endif |
| + .ndo_vlan_rx_add_vid = cpsw_ndo_vlan_rx_add_vid, |
| + .ndo_vlan_rx_kill_vid = cpsw_ndo_vlan_rx_kill_vid, |
| }; |
| |
| static void cpsw_get_drvinfo(struct net_device *ndev, |
| struct ethtool_drvinfo *info) |
| { |
| struct cpsw_priv *priv = netdev_priv(ndev); |
| - strcpy(info->driver, "TI CPSW Driver v1.0"); |
| - strcpy(info->version, "1.0"); |
| - strcpy(info->bus_info, priv->pdev->name); |
| + |
| + strlcpy(info->driver, "TI CPSW Driver v1.0", sizeof(info->driver)); |
| + strlcpy(info->version, "1.0", sizeof(info->version)); |
| + strlcpy(info->bus_info, priv->pdev->name, sizeof(info->bus_info)); |
| } |
| |
| static u32 cpsw_get_msglevel(struct net_device *ndev) |
| @@ -974,7 +1373,7 @@ static int cpsw_get_ts_info(struct net_device *ndev, |
| SOF_TIMESTAMPING_RX_SOFTWARE | |
| SOF_TIMESTAMPING_SOFTWARE | |
| SOF_TIMESTAMPING_RAW_HARDWARE; |
| - info->phc_index = priv->cpts.phc_index; |
| + info->phc_index = priv->cpts->phc_index; |
| info->tx_types = |
| (1 << HWTSTAMP_TX_OFF) | |
| (1 << HWTSTAMP_TX_ON); |
| @@ -993,12 +1392,39 @@ static int cpsw_get_ts_info(struct net_device *ndev, |
| return 0; |
| } |
| |
| +static int cpsw_get_settings(struct net_device *ndev, |
| + struct ethtool_cmd *ecmd) |
| +{ |
| + struct cpsw_priv *priv = netdev_priv(ndev); |
| + int slave_no = cpsw_slave_index(priv); |
| + |
| + if (priv->slaves[slave_no].phy) |
| + return phy_ethtool_gset(priv->slaves[slave_no].phy, ecmd); |
| + else |
| + return -EOPNOTSUPP; |
| +} |
| + |
| +static int cpsw_set_settings(struct net_device *ndev, struct ethtool_cmd *ecmd) |
| +{ |
| + struct cpsw_priv *priv = netdev_priv(ndev); |
| + int slave_no = cpsw_slave_index(priv); |
| + |
| + if (priv->slaves[slave_no].phy) |
| + return phy_ethtool_sset(priv->slaves[slave_no].phy, ecmd); |
| + else |
| + return -EOPNOTSUPP; |
| +} |
| + |
| static const struct ethtool_ops cpsw_ethtool_ops = { |
| .get_drvinfo = cpsw_get_drvinfo, |
| .get_msglevel = cpsw_get_msglevel, |
| .set_msglevel = cpsw_set_msglevel, |
| .get_link = ethtool_op_get_link, |
| .get_ts_info = cpsw_get_ts_info, |
| + .get_settings = cpsw_get_settings, |
| + .set_settings = cpsw_set_settings, |
| + .get_coalesce = cpsw_get_coalesce, |
| + .set_coalesce = cpsw_set_coalesce, |
| }; |
| |
| static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, |
| @@ -1011,6 +1437,7 @@ static void cpsw_slave_init(struct cpsw_slave *slave, struct cpsw_priv *priv, |
| slave->data = data; |
| slave->regs = regs + slave_reg_ofs; |
| slave->sliver = regs + sliver_reg_ofs; |
| + slave->port_vlan = data->dual_emac_res_vlan; |
| } |
| |
| static int cpsw_probe_dt(struct cpsw_platform_data *data, |
| @@ -1030,12 +1457,12 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, |
| } |
| data->slaves = prop; |
| |
| - if (of_property_read_u32(node, "cpts_active_slave", &prop)) { |
| - pr_err("Missing cpts_active_slave property in the DT.\n"); |
| + if (of_property_read_u32(node, "active_slave", &prop)) { |
| + pr_err("Missing active_slave property in the DT.\n"); |
| ret = -EINVAL; |
| goto error_ret; |
| } |
| - data->cpts_active_slave = prop; |
| + data->active_slave = prop; |
| |
| if (of_property_read_u32(node, "cpts_clock_mult", &prop)) { |
| pr_err("Missing cpts_clock_mult property in the DT.\n"); |
| @@ -1051,12 +1478,10 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, |
| } |
| data->cpts_clock_shift = prop; |
| |
| - data->slave_data = kzalloc(sizeof(struct cpsw_slave_data) * |
| - data->slaves, GFP_KERNEL); |
| - if (!data->slave_data) { |
| - pr_err("Could not allocate slave memory.\n"); |
| + data->slave_data = kcalloc(data->slaves, sizeof(struct cpsw_slave_data), |
| + GFP_KERNEL); |
| + if (!data->slave_data) |
| return -EINVAL; |
| - } |
| |
| if (of_property_read_u32(node, "cpdma_channels", &prop)) { |
| pr_err("Missing cpdma_channels property in the DT.\n"); |
| @@ -1093,6 +1518,9 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, |
| } |
| data->mac_control = prop; |
| |
| + if (!of_property_read_u32(node, "dual_emac", &prop)) |
| + data->dual_emac = prop; |
| + |
| /* |
| * Populate all the child nodes here... |
| */ |
| @@ -1111,7 +1539,7 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, |
| struct platform_device *mdio; |
| |
| parp = of_get_property(slave_node, "phy_id", &lenp); |
| - if ((parp == NULL) && (lenp != (sizeof(void *) * 2))) { |
| + if ((parp == NULL) || (lenp != (sizeof(void *) * 2))) { |
| pr_err("Missing slave[%d] phy_id property\n", i); |
| ret = -EINVAL; |
| goto error_ret; |
| @@ -1126,6 +1554,18 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, |
| if (mac_addr) |
| memcpy(slave_data->mac_addr, mac_addr, ETH_ALEN); |
| |
| + if (data->dual_emac) { |
| + if (of_property_read_u32(slave_node, "dual_emac_res_vlan", |
| + &prop)) { |
| + pr_err("Missing dual_emac_res_vlan in DT.\n"); |
| + slave_data->dual_emac_res_vlan = i+1; |
| + pr_err("Using %d as Reserved VLAN for %d slave\n", |
| + slave_data->dual_emac_res_vlan, i); |
| + } else { |
| + slave_data->dual_emac_res_vlan = prop; |
| + } |
| + } |
| + |
| i++; |
| } |
| |
| @@ -1136,9 +1576,85 @@ static int cpsw_probe_dt(struct cpsw_platform_data *data, |
| return ret; |
| } |
| |
| +static int cpsw_probe_dual_emac(struct platform_device *pdev, |
| + struct cpsw_priv *priv) |
| +{ |
| + struct cpsw_platform_data *data = &priv->data; |
| + struct net_device *ndev; |
| + struct cpsw_priv *priv_sl2; |
| + int ret = 0, i; |
| + |
| + ndev = alloc_etherdev(sizeof(struct cpsw_priv)); |
| + if (!ndev) { |
| + pr_err("cpsw: error allocating net_device\n"); |
| + return -ENOMEM; |
| + } |
| + |
| + priv_sl2 = netdev_priv(ndev); |
| + spin_lock_init(&priv_sl2->lock); |
| + priv_sl2->data = *data; |
| + priv_sl2->pdev = pdev; |
| + priv_sl2->ndev = ndev; |
| + priv_sl2->dev = &ndev->dev; |
| + priv_sl2->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); |
| + priv_sl2->rx_packet_max = max(rx_packet_max, 128); |
| + |
| + if (is_valid_ether_addr(data->slave_data[1].mac_addr)) { |
| + memcpy(priv_sl2->mac_addr, data->slave_data[1].mac_addr, |
| + ETH_ALEN); |
| + pr_info("cpsw: Detected MACID = %pM\n", priv_sl2->mac_addr); |
| + } else { |
| + random_ether_addr(priv_sl2->mac_addr); |
| + pr_info("cpsw: Random MACID = %pM\n", priv_sl2->mac_addr); |
| + } |
| + memcpy(ndev->dev_addr, priv_sl2->mac_addr, ETH_ALEN); |
| + |
| + priv_sl2->slaves = priv->slaves; |
| + priv_sl2->clk = priv->clk; |
| + |
| + priv_sl2->coal_intvl = 0; |
| + priv_sl2->bus_freq_mhz = priv->bus_freq_mhz; |
| + |
| + priv_sl2->cpsw_res = priv->cpsw_res; |
| + priv_sl2->regs = priv->regs; |
| + priv_sl2->host_port = priv->host_port; |
| + priv_sl2->host_port_regs = priv->host_port_regs; |
| + priv_sl2->wr_regs = priv->wr_regs; |
| + priv_sl2->dma = priv->dma; |
| + priv_sl2->txch = priv->txch; |
| + priv_sl2->rxch = priv->rxch; |
| + priv_sl2->ale = priv->ale; |
| + priv_sl2->emac_port = 1; |
| + priv->slaves[1].ndev = ndev; |
| + priv_sl2->cpts = priv->cpts; |
| + priv_sl2->version = priv->version; |
| + |
| + for (i = 0; i < priv->num_irqs; i++) { |
| + priv_sl2->irqs_table[i] = priv->irqs_table[i]; |
| + priv_sl2->num_irqs = priv->num_irqs; |
| + } |
| + priv->irq_enabled = true; |
| + ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; |
| + |
| + ndev->netdev_ops = &cpsw_netdev_ops; |
| + SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops); |
| + netif_napi_add(ndev, &priv_sl2->napi, cpsw_poll, CPSW_POLL_WEIGHT); |
| + |
| + /* register the network device */ |
| + SET_NETDEV_DEV(ndev, &pdev->dev); |
| + ret = register_netdev(ndev); |
| + if (ret) { |
| + pr_err("cpsw: error registering net device\n"); |
| + free_netdev(ndev); |
| + ret = -ENODEV; |
| + } |
| + |
| + return ret; |
| +} |
| + |
| static int cpsw_probe(struct platform_device *pdev) |
| { |
| - struct cpsw_platform_data *data = pdev->dev.platform_data; |
| + struct cpsw_platform_data *data; |
| struct net_device *ndev; |
| struct cpsw_priv *priv; |
| struct cpdma_params dma_params; |
| @@ -1162,6 +1678,11 @@ static int cpsw_probe(struct platform_device *pdev) |
| priv->dev = &ndev->dev; |
| priv->msg_enable = netif_msg_init(debug_level, CPSW_DEBUG); |
| priv->rx_packet_max = max(rx_packet_max, 128); |
| + priv->cpts = devm_kzalloc(&pdev->dev, sizeof(struct cpts), GFP_KERNEL); |
| + if (!ndev) { |
| + pr_err("error allocating cpts\n"); |
| + goto clean_ndev_ret; |
| + } |
| |
| /* |
| * This may be required here for child devices. |
| @@ -1194,12 +1715,17 @@ static int cpsw_probe(struct platform_device *pdev) |
| for (i = 0; i < data->slaves; i++) |
| priv->slaves[i].slave_num = i; |
| |
| + priv->slaves[0].ndev = ndev; |
| + priv->emac_port = 0; |
| + |
| priv->clk = clk_get(&pdev->dev, "fck"); |
| if (IS_ERR(priv->clk)) { |
| dev_err(&pdev->dev, "fck is not found\n"); |
| ret = -ENODEV; |
| goto clean_slave_ret; |
| } |
| + priv->coal_intvl = 0; |
| + priv->bus_freq_mhz = clk_get_rate(priv->clk) / 1000000; |
| |
| priv->cpsw_res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| if (!priv->cpsw_res) { |
| @@ -1248,7 +1774,7 @@ static int cpsw_probe(struct platform_device *pdev) |
| switch (priv->version) { |
| case CPSW_VERSION_1: |
| priv->host_port_regs = ss_regs + CPSW1_HOST_PORT_OFFSET; |
| - priv->cpts.reg = ss_regs + CPSW1_CPTS_OFFSET; |
| + priv->cpts->reg = ss_regs + CPSW1_CPTS_OFFSET; |
| dma_params.dmaregs = ss_regs + CPSW1_CPDMA_OFFSET; |
| dma_params.txhdp = ss_regs + CPSW1_STATERAM_OFFSET; |
| ale_params.ale_regs = ss_regs + CPSW1_ALE_OFFSET; |
| @@ -1259,7 +1785,7 @@ static int cpsw_probe(struct platform_device *pdev) |
| break; |
| case CPSW_VERSION_2: |
| priv->host_port_regs = ss_regs + CPSW2_HOST_PORT_OFFSET; |
| - priv->cpts.reg = ss_regs + CPSW2_CPTS_OFFSET; |
| + priv->cpts->reg = ss_regs + CPSW2_CPTS_OFFSET; |
| dma_params.dmaregs = ss_regs + CPSW2_CPDMA_OFFSET; |
| dma_params.txhdp = ss_regs + CPSW2_STATERAM_OFFSET; |
| ale_params.ale_regs = ss_regs + CPSW2_ALE_OFFSET; |
| @@ -1341,12 +1867,12 @@ static int cpsw_probe(struct platform_device *pdev) |
| goto clean_ale_ret; |
| } |
| priv->irqs_table[k] = i; |
| - priv->num_irqs = k; |
| + priv->num_irqs = k + 1; |
| } |
| k++; |
| } |
| |
| - ndev->flags |= IFF_ALLMULTI; /* see cpsw_ndo_change_rx_flags() */ |
| + ndev->features |= NETIF_F_HW_VLAN_CTAG_FILTER; |
| |
| ndev->netdev_ops = &cpsw_netdev_ops; |
| SET_ETHTOOL_OPS(ndev, &cpsw_ethtool_ops); |
| @@ -1361,17 +1887,26 @@ static int cpsw_probe(struct platform_device *pdev) |
| goto clean_irq_ret; |
| } |
| |
| - if (cpts_register(&pdev->dev, &priv->cpts, |
| + if (cpts_register(&pdev->dev, priv->cpts, |
| data->cpts_clock_mult, data->cpts_clock_shift)) |
| dev_err(priv->dev, "error registering cpts device\n"); |
| |
| cpsw_notice(priv, probe, "initialized device (regs %x, irq %d)\n", |
| priv->cpsw_res->start, ndev->irq); |
| |
| + if (priv->data.dual_emac) { |
| + ret = cpsw_probe_dual_emac(pdev, priv); |
| + if (ret) { |
| + cpsw_err(priv, probe, "error probe slave 2 emac interface\n"); |
| + goto clean_irq_ret; |
| + } |
| + } |
| + |
| return 0; |
| |
| clean_irq_ret: |
| - free_irq(ndev->irq, priv); |
| + for (i = 0; i < priv->num_irqs; i++) |
| + free_irq(priv->irqs_table[i], priv); |
| clean_ale_ret: |
| cpsw_ale_destroy(priv->ale); |
| clean_dma_ret: |
| @@ -1394,7 +1929,8 @@ static int cpsw_probe(struct platform_device *pdev) |
| pm_runtime_disable(&pdev->dev); |
| kfree(priv->slaves); |
| clean_ndev_ret: |
| - free_netdev(ndev); |
| + kfree(priv->data.slave_data); |
| + free_netdev(priv->ndev); |
| return ret; |
| } |
| |
| @@ -1402,12 +1938,17 @@ static int cpsw_remove(struct platform_device *pdev) |
| { |
| struct net_device *ndev = platform_get_drvdata(pdev); |
| struct cpsw_priv *priv = netdev_priv(ndev); |
| + int i; |
| |
| - pr_info("removing device"); |
| platform_set_drvdata(pdev, NULL); |
| + if (priv->data.dual_emac) |
| + unregister_netdev(cpsw_get_slave_ndev(priv, 1)); |
| + unregister_netdev(ndev); |
| + |
| + cpts_unregister(priv->cpts); |
| + for (i = 0; i < priv->num_irqs; i++) |
| + free_irq(priv->irqs_table[i], priv); |
| |
| - cpts_unregister(&priv->cpts); |
| - free_irq(ndev->irq, priv); |
| cpsw_ale_destroy(priv->ale); |
| cpdma_chan_destroy(priv->txch); |
| cpdma_chan_destroy(priv->rxch); |
| @@ -1421,8 +1962,10 @@ static int cpsw_remove(struct platform_device *pdev) |
| pm_runtime_disable(&pdev->dev); |
| clk_put(priv->clk); |
| kfree(priv->slaves); |
| + kfree(priv->data.slave_data); |
| + if (priv->data.dual_emac) |
| + free_netdev(cpsw_get_slave_ndev(priv, 1)); |
| free_netdev(ndev); |
| - |
| return 0; |
| } |
| |
| @@ -1458,6 +2001,7 @@ static const struct of_device_id cpsw_of_mtable[] = { |
| { .compatible = "ti,cpsw", }, |
| { /* sentinel */ }, |
| }; |
| +MODULE_DEVICE_TABLE(of, cpsw_of_mtable); |
| |
| static struct platform_driver cpsw_driver = { |
| .driver = { |
| diff --git a/drivers/net/ethernet/ti/cpsw_ale.c b/drivers/net/ethernet/ti/cpsw_ale.c |
| index 0e9ccc2..7fa60d6 100644 |
| --- a/drivers/net/ethernet/ti/cpsw_ale.c |
| +++ b/drivers/net/ethernet/ti/cpsw_ale.c |
| @@ -148,7 +148,7 @@ static int cpsw_ale_write(struct cpsw_ale *ale, int idx, u32 *ale_entry) |
| return idx; |
| } |
| |
| -static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr) |
| +int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr, u16 vid) |
| { |
| u32 ale_entry[ALE_ENTRY_WORDS]; |
| int type, idx; |
| @@ -160,6 +160,8 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr) |
| type = cpsw_ale_get_entry_type(ale_entry); |
| if (type != ALE_TYPE_ADDR && type != ALE_TYPE_VLAN_ADDR) |
| continue; |
| + if (cpsw_ale_get_vlan_id(ale_entry) != vid) |
| + continue; |
| cpsw_ale_get_addr(ale_entry, entry_addr); |
| if (memcmp(entry_addr, addr, 6) == 0) |
| return idx; |
| @@ -167,6 +169,22 @@ static int cpsw_ale_match_addr(struct cpsw_ale *ale, u8 *addr) |
| return -ENOENT; |
| } |
| |
| +int cpsw_ale_match_vlan(struct cpsw_ale *ale, u16 vid) |
| +{ |
| + u32 ale_entry[ALE_ENTRY_WORDS]; |
| + int type, idx; |
| + |
| + for (idx = 0; idx < ale->params.ale_entries; idx++) { |
| + cpsw_ale_read(ale, idx, ale_entry); |
| + type = cpsw_ale_get_entry_type(ale_entry); |
| + if (type != ALE_TYPE_VLAN) |
| + continue; |
| + if (cpsw_ale_get_vlan_id(ale_entry) == vid) |
| + return idx; |
| + } |
| + return -ENOENT; |
| +} |
| + |
| static int cpsw_ale_match_free(struct cpsw_ale *ale) |
| { |
| u32 ale_entry[ALE_ENTRY_WORDS]; |
| @@ -274,19 +292,32 @@ int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask) |
| return 0; |
| } |
| |
| -int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags) |
| +static inline void cpsw_ale_set_vlan_entry_type(u32 *ale_entry, |
| + int flags, u16 vid) |
| +{ |
| + if (flags & ALE_VLAN) { |
| + cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN_ADDR); |
| + cpsw_ale_set_vlan_id(ale_entry, vid); |
| + } else { |
| + cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); |
| + } |
| +} |
| + |
| +int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, |
| + int flags, u16 vid) |
| { |
| u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; |
| int idx; |
| |
| - cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); |
| + cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); |
| + |
| cpsw_ale_set_addr(ale_entry, addr); |
| cpsw_ale_set_ucast_type(ale_entry, ALE_UCAST_PERSISTANT); |
| cpsw_ale_set_secure(ale_entry, (flags & ALE_SECURE) ? 1 : 0); |
| cpsw_ale_set_blocked(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); |
| cpsw_ale_set_port_num(ale_entry, port); |
| |
| - idx = cpsw_ale_match_addr(ale, addr); |
| + idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); |
| if (idx < 0) |
| idx = cpsw_ale_match_free(ale); |
| if (idx < 0) |
| @@ -298,12 +329,13 @@ int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags) |
| return 0; |
| } |
| |
| -int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port) |
| +int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, |
| + int flags, u16 vid) |
| { |
| u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; |
| int idx; |
| |
| - idx = cpsw_ale_match_addr(ale, addr); |
| + idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); |
| if (idx < 0) |
| return -ENOENT; |
| |
| @@ -313,18 +345,19 @@ int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port) |
| } |
| |
| int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, |
| - int super, int mcast_state) |
| + int flags, u16 vid, int mcast_state) |
| { |
| u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; |
| int idx, mask; |
| |
| - idx = cpsw_ale_match_addr(ale, addr); |
| + idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); |
| if (idx >= 0) |
| cpsw_ale_read(ale, idx, ale_entry); |
| |
| - cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_ADDR); |
| + cpsw_ale_set_vlan_entry_type(ale_entry, flags, vid); |
| + |
| cpsw_ale_set_addr(ale_entry, addr); |
| - cpsw_ale_set_super(ale_entry, super); |
| + cpsw_ale_set_super(ale_entry, (flags & ALE_BLOCKED) ? 1 : 0); |
| cpsw_ale_set_mcast_state(ale_entry, mcast_state); |
| |
| mask = cpsw_ale_get_port_mask(ale_entry); |
| @@ -342,12 +375,13 @@ int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, |
| return 0; |
| } |
| |
| -int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask) |
| +int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, |
| + int flags, u16 vid) |
| { |
| u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; |
| int idx; |
| |
| - idx = cpsw_ale_match_addr(ale, addr); |
| + idx = cpsw_ale_match_addr(ale, addr, (flags & ALE_VLAN) ? vid : 0); |
| if (idx < 0) |
| return -EINVAL; |
| |
| @@ -362,6 +396,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask) |
| return 0; |
| } |
| |
| +int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, |
| + int reg_mcast, int unreg_mcast) |
| +{ |
| + u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; |
| + int idx; |
| + |
| + idx = cpsw_ale_match_vlan(ale, vid); |
| + if (idx >= 0) |
| + cpsw_ale_read(ale, idx, ale_entry); |
| + |
| + cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_VLAN); |
| + cpsw_ale_set_vlan_id(ale_entry, vid); |
| + |
| + cpsw_ale_set_vlan_untag_force(ale_entry, untag); |
| + cpsw_ale_set_vlan_reg_mcast(ale_entry, reg_mcast); |
| + cpsw_ale_set_vlan_unreg_mcast(ale_entry, unreg_mcast); |
| + cpsw_ale_set_vlan_member_list(ale_entry, port); |
| + |
| + if (idx < 0) |
| + idx = cpsw_ale_match_free(ale); |
| + if (idx < 0) |
| + idx = cpsw_ale_find_ageable(ale); |
| + if (idx < 0) |
| + return -ENOMEM; |
| + |
| + cpsw_ale_write(ale, idx, ale_entry); |
| + return 0; |
| +} |
| + |
| +int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port_mask) |
| +{ |
| + u32 ale_entry[ALE_ENTRY_WORDS] = {0, 0, 0}; |
| + int idx; |
| + |
| + idx = cpsw_ale_match_vlan(ale, vid); |
| + if (idx < 0) |
| + return -ENOENT; |
| + |
| + cpsw_ale_read(ale, idx, ale_entry); |
| + |
| + if (port_mask) |
| + cpsw_ale_set_vlan_member_list(ale_entry, port_mask); |
| + else |
| + cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE); |
| + |
| + cpsw_ale_write(ale, idx, ale_entry); |
| + return 0; |
| +} |
| + |
| struct ale_control_info { |
| const char *name; |
| int offset, port_offset; |
| diff --git a/drivers/net/ethernet/ti/cpsw_ale.h b/drivers/net/ethernet/ti/cpsw_ale.h |
| index 2bd09cb..30daa12 100644 |
| --- a/drivers/net/ethernet/ti/cpsw_ale.h |
| +++ b/drivers/net/ethernet/ti/cpsw_ale.h |
| @@ -64,8 +64,14 @@ enum cpsw_ale_port_state { |
| }; |
| |
| /* ALE unicast entry flags - passed into cpsw_ale_add_ucast() */ |
| -#define ALE_SECURE 1 |
| -#define ALE_BLOCKED 2 |
| +#define ALE_SECURE BIT(0) |
| +#define ALE_BLOCKED BIT(1) |
| +#define ALE_SUPER BIT(2) |
| +#define ALE_VLAN BIT(3) |
| + |
| +#define ALE_PORT_HOST BIT(0) |
| +#define ALE_PORT_1 BIT(1) |
| +#define ALE_PORT_2 BIT(2) |
| |
| #define ALE_MCAST_FWD 0 |
| #define ALE_MCAST_BLOCK_LEARN_FWD 1 |
| @@ -81,11 +87,17 @@ void cpsw_ale_stop(struct cpsw_ale *ale); |
| int cpsw_ale_set_ageout(struct cpsw_ale *ale, int ageout); |
| int cpsw_ale_flush(struct cpsw_ale *ale, int port_mask); |
| int cpsw_ale_flush_multicast(struct cpsw_ale *ale, int port_mask); |
| -int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, int flags); |
| -int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port); |
| +int cpsw_ale_add_ucast(struct cpsw_ale *ale, u8 *addr, int port, |
| + int flags, u16 vid); |
| +int cpsw_ale_del_ucast(struct cpsw_ale *ale, u8 *addr, int port, |
| + int flags, u16 vid); |
| int cpsw_ale_add_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, |
| - int super, int mcast_state); |
| -int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask); |
| + int flags, u16 vid, int mcast_state); |
| +int cpsw_ale_del_mcast(struct cpsw_ale *ale, u8 *addr, int port_mask, |
| + int flags, u16 vid); |
| +int cpsw_ale_add_vlan(struct cpsw_ale *ale, u16 vid, int port, int untag, |
| + int reg_mcast, int unreg_mcast); |
| +int cpsw_ale_del_vlan(struct cpsw_ale *ale, u16 vid, int port); |
| |
| int cpsw_ale_control_get(struct cpsw_ale *ale, int port, int control); |
| int cpsw_ale_control_set(struct cpsw_ale *ale, int port, |
| diff --git a/drivers/net/ethernet/ti/davinci_cpdma.c b/drivers/net/ethernet/ti/davinci_cpdma.c |
| index 4995673..49dfd59 100644 |
| --- a/drivers/net/ethernet/ti/davinci_cpdma.c |
| +++ b/drivers/net/ethernet/ti/davinci_cpdma.c |
| @@ -20,6 +20,7 @@ |
| #include <linux/err.h> |
| #include <linux/dma-mapping.h> |
| #include <linux/io.h> |
| +#include <linux/delay.h> |
| |
| #include "davinci_cpdma.h" |
| |
| @@ -60,6 +61,9 @@ |
| #define CPDMA_DESC_EOQ BIT(28) |
| #define CPDMA_DESC_TD_COMPLETE BIT(27) |
| #define CPDMA_DESC_PASS_CRC BIT(26) |
| +#define CPDMA_DESC_TO_PORT_EN BIT(20) |
| +#define CPDMA_TO_PORT_SHIFT 16 |
| +#define CPDMA_DESC_PORT_MASK (BIT(18) | BIT(17) | BIT(16)) |
| |
| #define CPDMA_TEARDOWN_VALUE 0xfffffffc |
| |
| @@ -105,13 +109,13 @@ struct cpdma_ctlr { |
| }; |
| |
| struct cpdma_chan { |
| + struct cpdma_desc __iomem *head, *tail; |
| + void __iomem *hdp, *cp, *rxfree; |
| enum cpdma_state state; |
| struct cpdma_ctlr *ctlr; |
| int chan_num; |
| spinlock_t lock; |
| - struct cpdma_desc __iomem *head, *tail; |
| int count; |
| - void __iomem *hdp, *cp, *rxfree; |
| u32 mask; |
| cpdma_handler_fn handler; |
| enum dma_data_direction dir; |
| @@ -132,6 +136,14 @@ struct cpdma_chan { |
| #define chan_write(chan, fld, v) __raw_writel(v, (chan)->fld) |
| #define desc_write(desc, fld, v) __raw_writel((u32)(v), &(desc)->fld) |
| |
| +#define cpdma_desc_to_port(chan, mode, directed) \ |
| + do { \ |
| + if (!is_rx_chan(chan) && ((directed == 1) || \ |
| + (directed == 2))) \ |
| + mode |= (CPDMA_DESC_TO_PORT_EN | \ |
| + (directed << CPDMA_TO_PORT_SHIFT)); \ |
| + } while (0) |
| + |
| /* |
| * Utility constructs for a cpdma descriptor pool. Some devices (e.g. davinci |
| * emac) have dedicated on-chip memory for these descriptors. Some other |
| @@ -217,17 +229,27 @@ desc_from_phys(struct cpdma_desc_pool *pool, dma_addr_t dma) |
| } |
| |
| static struct cpdma_desc __iomem * |
| -cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc) |
| +cpdma_desc_alloc(struct cpdma_desc_pool *pool, int num_desc, bool is_rx) |
| { |
| unsigned long flags; |
| int index; |
| + int desc_start; |
| + int desc_end; |
| struct cpdma_desc __iomem *desc = NULL; |
| |
| spin_lock_irqsave(&pool->lock, flags); |
| |
| - index = bitmap_find_next_zero_area(pool->bitmap, pool->num_desc, 0, |
| - num_desc, 0); |
| - if (index < pool->num_desc) { |
| + if (is_rx) { |
| + desc_start = 0; |
| + desc_end = pool->num_desc/2; |
| + } else { |
| + desc_start = pool->num_desc/2; |
| + desc_end = pool->num_desc; |
| + } |
| + |
| + index = bitmap_find_next_zero_area(pool->bitmap, |
| + desc_end, desc_start, num_desc, 0); |
| + if (index < desc_end) { |
| bitmap_set(pool->bitmap, index, num_desc); |
| desc = pool->iomap + pool->desc_size * index; |
| pool->used_desc++; |
| @@ -291,14 +313,16 @@ int cpdma_ctlr_start(struct cpdma_ctlr *ctlr) |
| } |
| |
| if (ctlr->params.has_soft_reset) { |
| - unsigned long timeout = jiffies + HZ/10; |
| + unsigned timeout = 10 * 100; |
| |
| dma_reg_write(ctlr, CPDMA_SOFTRESET, 1); |
| - while (time_before(jiffies, timeout)) { |
| + while (timeout) { |
| if (dma_reg_read(ctlr, CPDMA_SOFTRESET) == 0) |
| break; |
| + udelay(10); |
| + timeout--; |
| } |
| - WARN_ON(!time_before(jiffies, timeout)); |
| + WARN_ON(!timeout); |
| } |
| |
| for (i = 0; i < ctlr->num_chan; i++) { |
| @@ -439,10 +463,8 @@ int cpdma_ctlr_destroy(struct cpdma_ctlr *ctlr) |
| if (ctlr->state != CPDMA_STATE_IDLE) |
| cpdma_ctlr_stop(ctlr); |
| |
| - for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) { |
| - if (ctlr->channels[i]) |
| - cpdma_chan_destroy(ctlr->channels[i]); |
| - } |
| + for (i = 0; i < ARRAY_SIZE(ctlr->channels); i++) |
| + cpdma_chan_destroy(ctlr->channels[i]); |
| |
| cpdma_desc_pool_destroy(ctlr->pool); |
| spin_unlock_irqrestore(&ctlr->lock, flags); |
| @@ -473,11 +495,13 @@ int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable) |
| spin_unlock_irqrestore(&ctlr->lock, flags); |
| return 0; |
| } |
| +EXPORT_SYMBOL_GPL(cpdma_ctlr_int_ctrl); |
| |
| -void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr) |
| +void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value) |
| { |
| - dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, 0); |
| + dma_reg_write(ctlr, CPDMA_MACEOIVECTOR, value); |
| } |
| +EXPORT_SYMBOL_GPL(cpdma_ctlr_eoi); |
| |
| struct cpdma_chan *cpdma_chan_create(struct cpdma_ctlr *ctlr, int chan_num, |
| cpdma_handler_fn handler) |
| @@ -652,7 +676,7 @@ static void __cpdma_chan_submit(struct cpdma_chan *chan, |
| } |
| |
| int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, |
| - int len, gfp_t gfp_mask) |
| + int len, int directed) |
| { |
| struct cpdma_ctlr *ctlr = chan->ctlr; |
| struct cpdma_desc __iomem *desc; |
| @@ -668,7 +692,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, |
| goto unlock_ret; |
| } |
| |
| - desc = cpdma_desc_alloc(ctlr->pool, 1); |
| + desc = cpdma_desc_alloc(ctlr->pool, 1, is_rx_chan(chan)); |
| if (!desc) { |
| chan->stats.desc_alloc_fail++; |
| ret = -ENOMEM; |
| @@ -682,6 +706,7 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, |
| |
| buffer = dma_map_single(ctlr->dev, data, len, chan->dir); |
| mode = CPDMA_DESC_OWNER | CPDMA_DESC_SOP | CPDMA_DESC_EOP; |
| + cpdma_desc_to_port(chan, mode, directed); |
| |
| desc_write(desc, hw_next, 0); |
| desc_write(desc, hw_buffer, buffer); |
| @@ -704,6 +729,29 @@ int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, |
| } |
| EXPORT_SYMBOL_GPL(cpdma_chan_submit); |
| |
| +bool cpdma_check_free_tx_desc(struct cpdma_chan *chan) |
| +{ |
| + unsigned long flags; |
| + int index; |
| + bool ret; |
| + struct cpdma_ctlr *ctlr = chan->ctlr; |
| + struct cpdma_desc_pool *pool = ctlr->pool; |
| + |
| + spin_lock_irqsave(&pool->lock, flags); |
| + |
| + index = bitmap_find_next_zero_area(pool->bitmap, |
| + pool->num_desc, pool->num_desc/2, 1, 0); |
| + |
| + if (index < pool->num_desc) |
| + ret = true; |
| + else |
| + ret = false; |
| + |
| + spin_unlock_irqrestore(&pool->lock, flags); |
| + return ret; |
| +} |
| +EXPORT_SYMBOL_GPL(cpdma_check_free_tx_desc); |
| + |
| static void __cpdma_chan_free(struct cpdma_chan *chan, |
| struct cpdma_desc __iomem *desc, |
| int outlen, int status) |
| @@ -728,6 +776,7 @@ static int __cpdma_chan_process(struct cpdma_chan *chan) |
| struct cpdma_ctlr *ctlr = chan->ctlr; |
| struct cpdma_desc __iomem *desc; |
| int status, outlen; |
| + int cb_status = 0; |
| struct cpdma_desc_pool *pool = ctlr->pool; |
| dma_addr_t desc_dma; |
| unsigned long flags; |
| @@ -749,7 +798,8 @@ static int __cpdma_chan_process(struct cpdma_chan *chan) |
| status = -EBUSY; |
| goto unlock_ret; |
| } |
| - status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE); |
| + status = status & (CPDMA_DESC_EOQ | CPDMA_DESC_TD_COMPLETE | |
| + CPDMA_DESC_PORT_MASK); |
| |
| chan->head = desc_from_phys(pool, desc_read(desc, hw_next)); |
| chan_write(chan, cp, desc_dma); |
| @@ -762,8 +812,12 @@ static int __cpdma_chan_process(struct cpdma_chan *chan) |
| } |
| |
| spin_unlock_irqrestore(&chan->lock, flags); |
| + if (unlikely(status & CPDMA_DESC_TD_COMPLETE)) |
| + cb_status = -ENOSYS; |
| + else |
| + cb_status = status; |
| |
| - __cpdma_chan_free(chan, desc, outlen, status); |
| + __cpdma_chan_free(chan, desc, outlen, cb_status); |
| return status; |
| |
| unlock_ret: |
| @@ -822,7 +876,7 @@ int cpdma_chan_stop(struct cpdma_chan *chan) |
| struct cpdma_desc_pool *pool = ctlr->pool; |
| unsigned long flags; |
| int ret; |
| - unsigned long timeout; |
| + unsigned timeout; |
| |
| spin_lock_irqsave(&chan->lock, flags); |
| if (chan->state != CPDMA_STATE_ACTIVE) { |
| @@ -837,14 +891,15 @@ int cpdma_chan_stop(struct cpdma_chan *chan) |
| dma_reg_write(ctlr, chan->td, chan_linear(chan)); |
| |
| /* wait for teardown complete */ |
| - timeout = jiffies + HZ/10; /* 100 msec */ |
| - while (time_before(jiffies, timeout)) { |
| + timeout = 100 * 100; /* 100 ms */ |
| + while (timeout) { |
| u32 cp = chan_read(chan, cp); |
| if ((cp & CPDMA_TEARDOWN_VALUE) == CPDMA_TEARDOWN_VALUE) |
| break; |
| - cpu_relax(); |
| + udelay(10); |
| + timeout--; |
| } |
| - WARN_ON(!time_before(jiffies, timeout)); |
| + WARN_ON(!timeout); |
| chan_write(chan, cp, CPDMA_TEARDOWN_VALUE); |
| |
| /* handle completed packets */ |
| @@ -984,3 +1039,6 @@ int cpdma_control_set(struct cpdma_ctlr *ctlr, int control, int value) |
| spin_unlock_irqrestore(&ctlr->lock, flags); |
| return ret; |
| } |
| +EXPORT_SYMBOL_GPL(cpdma_control_set); |
| + |
| +MODULE_LICENSE("GPL"); |
| diff --git a/drivers/net/ethernet/ti/davinci_cpdma.h b/drivers/net/ethernet/ti/davinci_cpdma.h |
| index afa19a0..86dee48 100644 |
| --- a/drivers/net/ethernet/ti/davinci_cpdma.h |
| +++ b/drivers/net/ethernet/ti/davinci_cpdma.h |
| @@ -24,6 +24,13 @@ |
| #define __chan_linear(chan_num) ((chan_num) & (CPDMA_MAX_CHANNELS - 1)) |
| #define chan_linear(chan) __chan_linear((chan)->chan_num) |
| |
| +#define CPDMA_RX_SOURCE_PORT(__status__) ((__status__ >> 16) & 0x7) |
| + |
| +#define CPDMA_EOI_RX_THRESH 0x0 |
| +#define CPDMA_EOI_RX 0x1 |
| +#define CPDMA_EOI_TX 0x2 |
| +#define CPDMA_EOI_MISC 0x3 |
| + |
| struct cpdma_params { |
| struct device *dev; |
| void __iomem *dmaregs; |
| @@ -82,12 +89,13 @@ int cpdma_chan_dump(struct cpdma_chan *chan); |
| int cpdma_chan_get_stats(struct cpdma_chan *chan, |
| struct cpdma_chan_stats *stats); |
| int cpdma_chan_submit(struct cpdma_chan *chan, void *token, void *data, |
| - int len, gfp_t gfp_mask); |
| + int len, int directed); |
| int cpdma_chan_process(struct cpdma_chan *chan, int quota); |
| |
| int cpdma_ctlr_int_ctrl(struct cpdma_ctlr *ctlr, bool enable); |
| -void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr); |
| +void cpdma_ctlr_eoi(struct cpdma_ctlr *ctlr, u32 value); |
| int cpdma_chan_int_ctrl(struct cpdma_chan *chan, bool enable); |
| +bool cpdma_check_free_tx_desc(struct cpdma_chan *chan); |
| |
| enum cpdma_control { |
| CPDMA_CMD_IDLE, /* write-only */ |
| diff --git a/drivers/net/ethernet/ti/davinci_emac.c b/drivers/net/ethernet/ti/davinci_emac.c |
| index 2a3e2c5..860e15d 100644 |
| --- a/drivers/net/ethernet/ti/davinci_emac.c |
| +++ b/drivers/net/ethernet/ti/davinci_emac.c |
| @@ -120,7 +120,6 @@ static const char emac_version_string[] = "TI DaVinci EMAC Linux v6.1"; |
| #define EMAC_DEF_TX_CH (0) /* Default 0th channel */ |
| #define EMAC_DEF_RX_CH (0) /* Default 0th channel */ |
| #define EMAC_DEF_RX_NUM_DESC (128) |
| -#define EMAC_DEF_TX_NUM_DESC (128) |
| #define EMAC_DEF_MAX_TX_CH (1) /* Max TX channels configured */ |
| #define EMAC_DEF_MAX_RX_CH (1) /* Max RX channels configured */ |
| #define EMAC_POLL_WEIGHT (64) /* Default NAPI poll weight */ |
| @@ -342,7 +341,6 @@ struct emac_priv { |
| u32 mac_hash2; |
| u32 multicast_hash_cnt[EMAC_NUM_MULTICAST_BITS]; |
| u32 rx_addr_type; |
| - atomic_t cur_tx; |
| const char *phy_id; |
| #ifdef CONFIG_OF |
| struct device_node *phy_node; |
| @@ -480,8 +478,8 @@ static void emac_dump_regs(struct emac_priv *priv) |
| static void emac_get_drvinfo(struct net_device *ndev, |
| struct ethtool_drvinfo *info) |
| { |
| - strcpy(info->driver, emac_version_string); |
| - strcpy(info->version, EMAC_MODULE_VERSION); |
| + strlcpy(info->driver, emac_version_string, sizeof(info->driver)); |
| + strlcpy(info->version, EMAC_MODULE_VERSION, sizeof(info->version)); |
| } |
| |
| /** |
| @@ -1039,7 +1037,7 @@ static void emac_rx_handler(void *token, int len, int status) |
| |
| recycle: |
| ret = cpdma_chan_submit(priv->rxchan, skb, skb->data, |
| - skb_tailroom(skb), GFP_KERNEL); |
| + skb_tailroom(skb), 0); |
| |
| WARN_ON(ret == -ENOMEM); |
| if (unlikely(ret < 0)) |
| @@ -1050,12 +1048,12 @@ static void emac_tx_handler(void *token, int len, int status) |
| { |
| struct sk_buff *skb = token; |
| struct net_device *ndev = skb->dev; |
| - struct emac_priv *priv = netdev_priv(ndev); |
| - |
| - atomic_dec(&priv->cur_tx); |
| |
| + /* Check whether the queue is stopped due to stalled tx dma, if the |
| + * queue is stopped then start the queue as we have free desc for tx |
| + */ |
| if (unlikely(netif_queue_stopped(ndev))) |
| - netif_start_queue(ndev); |
| + netif_wake_queue(ndev); |
| ndev->stats.tx_packets++; |
| ndev->stats.tx_bytes += len; |
| dev_kfree_skb_any(skb); |
| @@ -1094,14 +1092,17 @@ static int emac_dev_xmit(struct sk_buff *skb, struct net_device *ndev) |
| skb_tx_timestamp(skb); |
| |
| ret_code = cpdma_chan_submit(priv->txchan, skb, skb->data, skb->len, |
| - GFP_KERNEL); |
| + 0); |
| if (unlikely(ret_code != 0)) { |
| if (netif_msg_tx_err(priv) && net_ratelimit()) |
| dev_err(emac_dev, "DaVinci EMAC: desc submit failed"); |
| goto fail_tx; |
| } |
| |
| - if (atomic_inc_return(&priv->cur_tx) >= EMAC_DEF_TX_NUM_DESC) |
| + /* If there is no more tx desc left free then we need to |
| + * tell the kernel to stop sending us tx frames. |
| + */ |
| + if (unlikely(!cpdma_check_free_tx_desc(priv->txchan))) |
| netif_stop_queue(ndev); |
| |
| return NETDEV_TX_OK; |
| @@ -1264,7 +1265,6 @@ static int emac_dev_setmac_addr(struct net_device *ndev, void *addr) |
| /* Store mac addr in priv and rx channel and set it in EMAC hw */ |
| memcpy(priv->mac_addr, sa->sa_data, ndev->addr_len); |
| memcpy(ndev->dev_addr, sa->sa_data, ndev->addr_len); |
| - ndev->addr_assign_type &= ~NET_ADDR_RANDOM; |
| |
| /* MAC address is configured only after the interface is enabled. */ |
| if (netif_running(ndev)) { |
| @@ -1438,7 +1438,7 @@ static int emac_poll(struct napi_struct *napi, int budget) |
| * Polled functionality used by netconsole and others in non interrupt mode |
| * |
| */ |
| -void emac_poll_controller(struct net_device *ndev) |
| +static void emac_poll_controller(struct net_device *ndev) |
| { |
| struct emac_priv *priv = netdev_priv(ndev); |
| |
| @@ -1558,7 +1558,7 @@ static int emac_dev_open(struct net_device *ndev) |
| break; |
| |
| ret = cpdma_chan_submit(priv->rxchan, skb, skb->data, |
| - skb_tailroom(skb), GFP_KERNEL); |
| + skb_tailroom(skb), 0); |
| if (WARN_ON(ret < 0)) |
| break; |
| } |
| @@ -1600,7 +1600,7 @@ static int emac_dev_open(struct net_device *ndev) |
| |
| if (priv->phy_id && *priv->phy_id) { |
| priv->phydev = phy_connect(ndev, priv->phy_id, |
| - &emac_adjust_link, 0, |
| + &emac_adjust_link, |
| PHY_INTERFACE_MODE_MII); |
| |
| if (IS_ERR(priv->phydev)) { |
| @@ -1865,21 +1865,18 @@ static int davinci_emac_probe(struct platform_device *pdev) |
| |
| |
| /* obtain emac clock from kernel */ |
| - emac_clk = clk_get(&pdev->dev, NULL); |
| + emac_clk = devm_clk_get(&pdev->dev, NULL); |
| if (IS_ERR(emac_clk)) { |
| dev_err(&pdev->dev, "failed to get EMAC clock\n"); |
| return -EBUSY; |
| } |
| emac_bus_frequency = clk_get_rate(emac_clk); |
| - clk_put(emac_clk); |
| |
| /* TODO: Probe PHY here if possible */ |
| |
| ndev = alloc_etherdev(sizeof(struct emac_priv)); |
| - if (!ndev) { |
| - rc = -ENOMEM; |
| - goto no_ndev; |
| - } |
| + if (!ndev) |
| + return -ENOMEM; |
| |
| platform_set_drvdata(pdev, ndev); |
| priv = netdev_priv(ndev); |
| @@ -1893,7 +1890,7 @@ static int davinci_emac_probe(struct platform_device *pdev) |
| if (!pdata) { |
| dev_err(&pdev->dev, "no platform data\n"); |
| rc = -ENODEV; |
| - goto probe_quit; |
| + goto no_pdata; |
| } |
| |
| /* MAC addr and PHY mask , RMII enable info from platform_data */ |
| @@ -1913,23 +1910,23 @@ static int davinci_emac_probe(struct platform_device *pdev) |
| if (!res) { |
| dev_err(&pdev->dev,"error getting res\n"); |
| rc = -ENOENT; |
| - goto probe_quit; |
| + goto no_pdata; |
| } |
| |
| priv->emac_base_phys = res->start + pdata->ctrl_reg_offset; |
| size = resource_size(res); |
| - if (!request_mem_region(res->start, size, ndev->name)) { |
| + if (!devm_request_mem_region(&pdev->dev, res->start, |
| + size, ndev->name)) { |
| dev_err(&pdev->dev, "failed request_mem_region() for regs\n"); |
| rc = -ENXIO; |
| - goto probe_quit; |
| + goto no_pdata; |
| } |
| |
| - priv->remap_addr = ioremap(res->start, size); |
| + priv->remap_addr = devm_ioremap(&pdev->dev, res->start, size); |
| if (!priv->remap_addr) { |
| dev_err(&pdev->dev, "unable to map IO\n"); |
| rc = -ENOMEM; |
| - release_mem_region(res->start, size); |
| - goto probe_quit; |
| + goto no_pdata; |
| } |
| priv->emac_base = priv->remap_addr + pdata->ctrl_reg_offset; |
| ndev->base_addr = (unsigned long)priv->remap_addr; |
| @@ -1962,7 +1959,7 @@ static int davinci_emac_probe(struct platform_device *pdev) |
| if (!priv->dma) { |
| dev_err(&pdev->dev, "error initializing DMA\n"); |
| rc = -ENOMEM; |
| - goto no_dma; |
| + goto no_pdata; |
| } |
| |
| priv->txchan = cpdma_chan_create(priv->dma, tx_chan_num(EMAC_DEF_TX_CH), |
| @@ -1971,14 +1968,14 @@ static int davinci_emac_probe(struct platform_device *pdev) |
| emac_rx_handler); |
| if (WARN_ON(!priv->txchan || !priv->rxchan)) { |
| rc = -ENOMEM; |
| - goto no_irq_res; |
| + goto no_cpdma_chan; |
| } |
| |
| res = platform_get_resource(pdev, IORESOURCE_IRQ, 0); |
| if (!res) { |
| dev_err(&pdev->dev, "error getting irq res\n"); |
| rc = -ENOENT; |
| - goto no_irq_res; |
| + goto no_cpdma_chan; |
| } |
| ndev->irq = res->start; |
| |
| @@ -2000,7 +1997,7 @@ static int davinci_emac_probe(struct platform_device *pdev) |
| if (rc) { |
| dev_err(&pdev->dev, "error in register_netdev\n"); |
| rc = -ENODEV; |
| - goto no_irq_res; |
| + goto no_cpdma_chan; |
| } |
| |
| |
| @@ -2015,20 +2012,14 @@ static int davinci_emac_probe(struct platform_device *pdev) |
| |
| return 0; |
| |
| -no_irq_res: |
| +no_cpdma_chan: |
| if (priv->txchan) |
| cpdma_chan_destroy(priv->txchan); |
| if (priv->rxchan) |
| cpdma_chan_destroy(priv->rxchan); |
| cpdma_ctlr_destroy(priv->dma); |
| -no_dma: |
| - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| - release_mem_region(res->start, resource_size(res)); |
| - iounmap(priv->remap_addr); |
| - |
| -probe_quit: |
| +no_pdata: |
| free_netdev(ndev); |
| -no_ndev: |
| return rc; |
| } |
| |
| @@ -2041,14 +2032,12 @@ static int davinci_emac_probe(struct platform_device *pdev) |
| */ |
| static int davinci_emac_remove(struct platform_device *pdev) |
| { |
| - struct resource *res; |
| struct net_device *ndev = platform_get_drvdata(pdev); |
| struct emac_priv *priv = netdev_priv(ndev); |
| |
| dev_notice(&ndev->dev, "DaVinci EMAC: davinci_emac_remove()\n"); |
| |
| platform_set_drvdata(pdev, NULL); |
| - res = platform_get_resource(pdev, IORESOURCE_MEM, 0); |
| |
| if (priv->txchan) |
| cpdma_chan_destroy(priv->txchan); |
| @@ -2056,10 +2045,7 @@ static int davinci_emac_remove(struct platform_device *pdev) |
| cpdma_chan_destroy(priv->rxchan); |
| cpdma_ctlr_destroy(priv->dma); |
| |
| - release_mem_region(res->start, resource_size(res)); |
| - |
| unregister_netdev(ndev); |
| - iounmap(priv->remap_addr); |
| free_netdev(ndev); |
| |
| return 0; |
| diff --git a/drivers/net/ethernet/ti/davinci_mdio.c b/drivers/net/ethernet/ti/davinci_mdio.c |
| index cca2550..12aec17 100644 |
| --- a/drivers/net/ethernet/ti/davinci_mdio.c |
| +++ b/drivers/net/ethernet/ti/davinci_mdio.c |
| @@ -320,10 +320,8 @@ static int davinci_mdio_probe(struct platform_device *pdev) |
| int ret, addr; |
| |
| data = kzalloc(sizeof(*data), GFP_KERNEL); |
| - if (!data) { |
| - dev_err(dev, "failed to alloc device data\n"); |
| + if (!data) |
| return -ENOMEM; |
| - } |
| |
| data->bus = mdiobus_alloc(); |
| if (!data->bus) { |
| @@ -487,6 +485,7 @@ static const struct of_device_id davinci_mdio_of_mtable[] = { |
| { .compatible = "ti,davinci_mdio", }, |
| { /* sentinel */ }, |
| }; |
| +MODULE_DEVICE_TABLE(of, davinci_mdio_of_mtable); |
| |
| static struct platform_driver davinci_mdio_driver = { |
| .driver = { |
| diff --git a/drivers/net/ethernet/ti/tlan.c b/drivers/net/ethernet/ti/tlan.c |
| index 2272538..60c400f 100644 |
| --- a/drivers/net/ethernet/ti/tlan.c |
| +++ b/drivers/net/ethernet/ti/tlan.c |
| @@ -320,6 +320,7 @@ static void tlan_remove_one(struct pci_dev *pdev) |
| free_netdev(dev); |
| |
| pci_set_drvdata(pdev, NULL); |
| + cancel_work_sync(&priv->tlan_tqueue); |
| } |
| |
| static void tlan_start(struct net_device *dev) |
| @@ -1911,10 +1912,8 @@ static void tlan_reset_lists(struct net_device *dev) |
| list->frame_size = TLAN_MAX_FRAME_SIZE; |
| list->buffer[0].count = TLAN_MAX_FRAME_SIZE | TLAN_LAST_BUFFER; |
| skb = netdev_alloc_skb_ip_align(dev, TLAN_MAX_FRAME_SIZE + 5); |
| - if (!skb) { |
| - netdev_err(dev, "Out of memory for received data\n"); |
| + if (!skb) |
| break; |
| - } |
| |
| list->buffer[0].address = pci_map_single(priv->pci_dev, |
| skb->data, |
| diff --git a/include/linux/platform_data/cpsw.h b/include/linux/platform_data/cpsw.h |
| index 24368a2..bb3cd58 100644 |
| --- a/include/linux/platform_data/cpsw.h |
| +++ b/include/linux/platform_data/cpsw.h |
| @@ -21,6 +21,8 @@ struct cpsw_slave_data { |
| char phy_id[MII_BUS_ID_SIZE]; |
| int phy_if; |
| u8 mac_addr[ETH_ALEN]; |
| + u16 dual_emac_res_vlan; /* Reserved VLAN for DualEMAC */ |
| + |
| }; |
| |
| struct cpsw_platform_data { |
| @@ -28,13 +30,15 @@ struct cpsw_platform_data { |
| u32 channels; /* number of cpdma channels (symmetric) */ |
| u32 slaves; /* number of slave cpgmac ports */ |
| struct cpsw_slave_data *slave_data; |
| - u32 cpts_active_slave; /* time stamping slave */ |
| + u32 active_slave; /* time stamping, ethtool and SIOCGMIIPHY slave */ |
| u32 cpts_clock_mult; /* convert input clock ticks to nanoseconds */ |
| u32 cpts_clock_shift; /* convert input clock ticks to nanoseconds */ |
| u32 ale_entries; /* ale table size */ |
| u32 bd_ram_size; /*buffer descriptor ram size */ |
| u32 rx_descs; /* Number of Rx Descriptios */ |
| u32 mac_control; /* Mac control register */ |
| + u16 default_vlan; /* Def VLAN for ALE lookup in VLAN aware mode*/ |
| + bool dual_emac; /* Enable Dual EMAC mode */ |
| }; |
| |
| #endif /* __CPSW_H__ */ |