aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorMugunthan V N <mugunthanvnm@ti.com>2013-02-11 04:52:20 -0500
committerDavid S. Miller <davem@davemloft.net>2013-02-12 16:15:10 -0500
commitd9ba8f9e6298af71ec1c1fd3d88c3ef68abd0ec3 (patch)
tree933b4cdcb097e37e8eaea6970f791e862040bd0b
parent9232b16df2167c8afcb89de39ee85f5091ebacff (diff)
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>
-rw-r--r--Documentation/devicetree/bindings/net/cpsw.txt2
-rw-r--r--drivers/net/ethernet/ti/cpsw.c335
-rw-r--r--include/linux/platform_data/cpsw.h3
3 files changed, 288 insertions, 52 deletions
diff --git a/Documentation/devicetree/bindings/net/cpsw.txt b/Documentation/devicetree/bindings/net/cpsw.txt
index 6ddd0286a9b7..ecfdf756d10f 100644
--- a/Documentation/devicetree/bindings/net/cpsw.txt
+++ b/Documentation/devicetree/bindings/net/cpsw.txt
@@ -24,6 +24,8 @@ Required properties:
24Optional properties: 24Optional properties:
25- ti,hwmods : Must be "cpgmac0" 25- ti,hwmods : Must be "cpgmac0"
26- no_bd_ram : Must be 0 or 1 26- no_bd_ram : Must be 0 or 1
27- dual_emac : Specifies Switch to act as Dual EMAC
28- dual_emac_res_vlan : Specifies VID to be used to segregate the ports
27 29
28Note: "ti,hwmods" field is used to fetch the base address and irq 30Note: "ti,hwmods" field is used to fetch the base address and irq
29resources from TI, omap hwmod data base during device registration. 31resources from TI, omap hwmod data base during device registration.
diff --git a/drivers/net/ethernet/ti/cpsw.c b/drivers/net/ethernet/ti/cpsw.c
index 4b964bb02d4c..4ceed6e0f1be 100644
--- a/drivers/net/ethernet/ti/cpsw.c
+++ b/drivers/net/ethernet/ti/cpsw.c
@@ -122,6 +122,10 @@ do { \
122#define CPSW_VLAN_AWARE BIT(1) 122#define CPSW_VLAN_AWARE BIT(1)
123#define CPSW_ALE_VLAN_AWARE 1 123#define CPSW_ALE_VLAN_AWARE 1
124 124
125#define CPSW_FIFO_NORMAL_MODE (0 << 15)
126#define CPSW_FIFO_DUAL_MAC_MODE (1 << 15)
127#define CPSW_FIFO_RATE_LIMIT_MODE (2 << 15)
128
125#define cpsw_enable_irq(priv) \ 129#define cpsw_enable_irq(priv) \
126 do { \ 130 do { \
127 u32 i; \ 131 u32 i; \
@@ -254,7 +258,7 @@ struct cpsw_ss_regs {
254struct cpsw_host_regs { 258struct cpsw_host_regs {
255 u32 max_blks; 259 u32 max_blks;
256 u32 blk_cnt; 260 u32 blk_cnt;
257 u32 flow_thresh; 261 u32 tx_in_ctl;
258 u32 port_vlan; 262 u32 port_vlan;
259 u32 tx_pri_map; 263 u32 tx_pri_map;
260 u32 cpdma_tx_pri_map; 264 u32 cpdma_tx_pri_map;
@@ -281,6 +285,9 @@ struct cpsw_slave {
281 u32 mac_control; 285 u32 mac_control;
282 struct cpsw_slave_data *data; 286 struct cpsw_slave_data *data;
283 struct phy_device *phy; 287 struct phy_device *phy;
288 struct net_device *ndev;
289 u32 port_vlan;
290 u32 open_stat;
284}; 291};
285 292
286static inline u32 slave_read(struct cpsw_slave *slave, u32 offset) 293static inline u32 slave_read(struct cpsw_slave *slave, u32 offset)
@@ -320,15 +327,63 @@ struct cpsw_priv {
320 u32 irqs_table[4]; 327 u32 irqs_table[4];
321 u32 num_irqs; 328 u32 num_irqs;
322 struct cpts *cpts; 329 struct cpts *cpts;
330 u32 emac_port;
323}; 331};
324 332
325#define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi) 333#define napi_to_priv(napi) container_of(napi, struct cpsw_priv, napi)
326#define for_each_slave(priv, func, arg...) \ 334#define for_each_slave(priv, func, arg...) \
327 do { \ 335 do { \
328 int idx; \ 336 int idx; \
329 for (idx = 0; idx < (priv)->data.slaves; idx++) \ 337 if (priv->data.dual_emac) \
330 (func)((priv)->slaves + idx, ##arg); \ 338 (func)((priv)->slaves + priv->emac_port, ##arg);\
339 else \
340 for (idx = 0; idx < (priv)->data.slaves; idx++) \
341 (func)((priv)->slaves + idx, ##arg); \
342 } while (0)
343#define cpsw_get_slave_ndev(priv, __slave_no__) \
344 (priv->slaves[__slave_no__].ndev)
345#define cpsw_get_slave_priv(priv, __slave_no__) \
346 ((priv->slaves[__slave_no__].ndev) ? \
347 netdev_priv(priv->slaves[__slave_no__].ndev) : NULL) \
348
349#define cpsw_dual_emac_src_port_detect(status, priv, ndev, skb) \
350 do { \
351 if (!priv->data.dual_emac) \
352 break; \
353 if (CPDMA_RX_SOURCE_PORT(status) == 1) { \
354 ndev = cpsw_get_slave_ndev(priv, 0); \
355 priv = netdev_priv(ndev); \
356 skb->dev = ndev; \
357 } else if (CPDMA_RX_SOURCE_PORT(status) == 2) { \
358 ndev = cpsw_get_slave_ndev(priv, 1); \
359 priv = netdev_priv(ndev); \
360 skb->dev = ndev; \
361 } \
331 } while (0) 362 } while (0)
363#define cpsw_add_mcast(priv, addr) \
364 do { \
365 if (priv->data.dual_emac) { \
366 struct cpsw_slave *slave = priv->slaves + \
367 priv->emac_port; \
368 int slave_port = cpsw_get_slave_port(priv, \
369 slave->slave_num); \
370 cpsw_ale_add_mcast(priv->ale, addr, \
371 1 << slave_port | 1 << priv->host_port, \
372 ALE_VLAN, slave->port_vlan, 0); \
373 } else { \
374 cpsw_ale_add_mcast(priv->ale, addr, \
375 ALE_ALL_PORTS << priv->host_port, \
376 0, 0, 0); \
377 } \
378 } while (0)
379
380static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
381{
382 if (priv->host_port == 0)
383 return slave_num + 1;
384 else
385 return slave_num;
386}
332 387
333static void cpsw_ndo_set_rx_mode(struct net_device *ndev) 388static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
334{ 389{
@@ -348,8 +403,7 @@ static void cpsw_ndo_set_rx_mode(struct net_device *ndev)
348 403
349 /* program multicast address list into ALE register */ 404 /* program multicast address list into ALE register */
350 netdev_for_each_mc_addr(ha, ndev) { 405 netdev_for_each_mc_addr(ha, ndev) {
351 cpsw_ale_add_mcast(priv->ale, (u8 *)ha->addr, 406 cpsw_add_mcast(priv, (u8 *)ha->addr);
352 ALE_ALL_PORTS << priv->host_port, 0, 0, 0);
353 } 407 }
354 } 408 }
355} 409}
@@ -396,6 +450,8 @@ void cpsw_rx_handler(void *token, int len, int status)
396 struct cpsw_priv *priv = netdev_priv(ndev); 450 struct cpsw_priv *priv = netdev_priv(ndev);
397 int ret = 0; 451 int ret = 0;
398 452
453 cpsw_dual_emac_src_port_detect(status, priv, ndev, skb);
454
399 /* free and bail if we are shutting down */ 455 /* free and bail if we are shutting down */
400 if (unlikely(!netif_running(ndev)) || 456 if (unlikely(!netif_running(ndev)) ||
401 unlikely(!netif_carrier_ok(ndev))) { 457 unlikely(!netif_carrier_ok(ndev))) {
@@ -437,18 +493,17 @@ static irqreturn_t cpsw_interrupt(int irq, void *dev_id)
437 cpsw_intr_disable(priv); 493 cpsw_intr_disable(priv);
438 cpsw_disable_irq(priv); 494 cpsw_disable_irq(priv);
439 napi_schedule(&priv->napi); 495 napi_schedule(&priv->napi);
496 } else {
497 priv = cpsw_get_slave_priv(priv, 1);
498 if (likely(priv) && likely(netif_running(priv->ndev))) {
499 cpsw_intr_disable(priv);
500 cpsw_disable_irq(priv);
501 napi_schedule(&priv->napi);
502 }
440 } 503 }
441 return IRQ_HANDLED; 504 return IRQ_HANDLED;
442} 505}
443 506
444static inline int cpsw_get_slave_port(struct cpsw_priv *priv, u32 slave_num)
445{
446 if (priv->host_port == 0)
447 return slave_num + 1;
448 else
449 return slave_num;
450}
451
452static int cpsw_poll(struct napi_struct *napi, int budget) 507static int cpsw_poll(struct napi_struct *napi, int budget)
453{ 508{
454 struct cpsw_priv *priv = napi_to_priv(napi); 509 struc