blob: b8cc13247af31580a60866040aacadaed54174fb [file] [log] [blame]
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>
---
---
arch/arm/boot/dts/am33xx.dtsi | 16
drivers/net/ethernet/ti/Kconfig | 4
drivers/net/ethernet/ti/cpmac.c | 11
drivers/net/ethernet/ti/cpsw.c | 814 ++++++++++++++++++++++++++------
drivers/net/ethernet/ti/cpsw_ale.c | 107 +++-
drivers/net/ethernet/ti/cpsw_ale.h | 24
drivers/net/ethernet/ti/davinci_cpdma.c | 106 +++-
drivers/net/ethernet/ti/davinci_cpdma.h | 12
drivers/net/ethernet/ti/davinci_emac.c | 76 +-
drivers/net/ethernet/ti/davinci_mdio.c | 5
drivers/net/ethernet/ti/tlan.c | 5
include/linux/platform_data/cpsw.h | 6
12 files changed, 946 insertions(+), 240 deletions(-)
--- 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";
+ };
};
};
--- 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
--- a/drivers/net/ethernet/ti/cpmac.c
+++ b/drivers/net/ethernet/ti/cpmac.c
@@ -904,10 +904,9 @@ static int cpmac_set_ringparam(struct ne
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_d
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))
--- 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,16 +348,68 @@ 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)
{
@@ -344,8 +429,7 @@ static void cpsw_ndo_set_rx_mode(struct
/* 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 le
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 le
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
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_
}
}
+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,
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_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_
}
}
+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 c
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_devi
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_devi
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(s
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(str
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
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
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
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 ne
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 n
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(str
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_
#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_d
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_d
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->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_pla
}
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_pla
}
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_pla
}
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_pla
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_pla
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 @@ error_ret:
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_de
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_de
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_de
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_de
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_de
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_de
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 @@ clean_slave_ret:
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_d
{
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_d
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
{ .compatible = "ti,cpsw", },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, cpsw_of_mtable);
static struct platform_driver cpsw_driver = {
.driver = {
--- 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_al
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 cp
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 cp
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,
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 *
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 *
}
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 *
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;
@@ -358,6 +392,55 @@ int cpsw_ale_del_mcast(struct cpsw_ale *
else
cpsw_ale_set_entry_type(ale_entry, ALE_TYPE_FREE);
+ cpsw_ale_write(ale, idx, ale_entry);
+ 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;
}
--- 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,
--- 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 *p
}
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 *
}
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
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_ctl
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 c
}
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
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
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 @@ unlock_ret:
}
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 c
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 c
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 c
}
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 *c
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 *c
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 @@ unlock_ret:
spin_unlock_irqrestore(&ctlr->lock, flags);
return ret;
}
+EXPORT_SYMBOL_GPL(cpdma_control_set);
+
+MODULE_LICENSE("GPL");
--- 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 *c
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 */
--- 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[]
#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_p
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,
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,
{
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_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 n
/* 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
* 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_devi
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_devi
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 pla
/* 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 pla
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 pla
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 pla
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 pla
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 pla
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 pla
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 @@ no_ndev:
*/
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 pl
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;
--- 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 pla
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
{ .compatible = "ti,davinci_mdio", },
{ /* sentinel */ },
};
+MODULE_DEVICE_TABLE(of, davinci_mdio_of_mtable);
static struct platform_driver davinci_mdio_driver = {
.driver = {
--- 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_d
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_
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,
--- 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__ */