/** * gelic_net_set_multi - sets multicast addresses and promisc flags * @netdev: interface device structure * * gelic_net_set_multi configures multicast addresses as needed for the * netdev interface. It also sets up multicast, allmulti and promisc * flags appropriately */ void gelic_net_set_multi(struct net_device *netdev) { struct gelic_card *card = netdev_card(netdev); struct dev_mc_list *mc; unsigned int i; uint8_t *p; u64 addr; int status; /* clear all multicast address */ status = lv1_net_remove_multicast_address(bus_id(card), dev_id(card), 0, 1); if (status) dev_err(ctodev(card), "lv1_net_remove_multicast_address failed %d\n", status); /* set broadcast address */ status = lv1_net_add_multicast_address(bus_id(card), dev_id(card), GELIC_NET_BROADCAST_ADDR, 0); if (status) dev_err(ctodev(card), "lv1_net_add_multicast_address failed, %d\n", status); if ((netdev->flags & IFF_ALLMULTI) || (netdev->mc_count > GELIC_NET_MC_COUNT_MAX)) { status = lv1_net_add_multicast_address(bus_id(card), dev_id(card), 0, 1); if (status) dev_err(ctodev(card), "lv1_net_add_multicast_address failed, %d\n", status); return; } /* set multicast addresses */ for (mc = netdev->mc_list; mc; mc = mc->next) { addr = 0; p = mc->dmi_addr; for (i = 0; i < ETH_ALEN; i++) { addr <<= 8; addr |= *p++; } status = lv1_net_add_multicast_address(bus_id(card), dev_id(card), addr, 0); if (status) dev_err(ctodev(card), "lv1_net_add_multicast_address failed, %d\n", status); } }
/** * gelic_net_kick_txdma - enables TX DMA processing * @card: card structure * @descr: descriptor address to enable TX processing at * */ static int gelic_net_kick_txdma(struct gelic_net_card *card, struct gelic_net_descr *descr) { int status = 0; int count = 10; if (card->tx_dma_progress) return 0; if (gelic_net_get_descr_status(descr) == GELIC_NET_DESCR_CARDOWNED) { card->tx_dma_progress = 1; /* sometimes we need retry here */ while (count--) { status = lv1_net_start_tx_dma(bus_id(card), dev_id(card), descr->bus_addr, 0); if (!status) break; } if (!count) dev_info(ctodev(card), "lv1_net_start_txdma failed," \ "status=%d %#lx\n", status, card->irq_status); } return status; }
/** * gelic_net_disable_txdmac - disables the transmit DMA controller * @card: card structure * * gelic_net_disable_txdmac terminates processing on the DMA controller by * turing off DMA and issueing a force end */ static inline void gelic_net_disable_txdmac(struct gelic_net_card *card) { int status; /* this hvc blocks until the DMA in progress really stopped */ status = lv1_net_stop_tx_dma(bus_id(card), dev_id(card), 0); if (status) dev_err(ctodev(card), "lv1_net_stop_tx_dma faild, status=%d\n", status); }
/** * gelic_net_enable_rxdmac - enables the receive DMA controller * @card: card structure * * gelic_net_enable_rxdmac enables the DMA controller by setting RX_DMA_EN * in the GDADMACCNTR register */ static inline void gelic_net_enable_rxdmac(struct gelic_net_card *card) { int status; status = lv1_net_start_rx_dma(bus_id(card), dev_id(card), card->rx_chain.tail->bus_addr, 0); if (status) dev_info(ctodev(card), "lv1_net_start_rx_dma failed, status=%d\n", status); }
/** * gelic_card_disable_rxdmac - disables the receive DMA controller * @card: card structure * * gelic_card_disable_rxdmac terminates processing on the DMA controller by * turing off DMA and issuing a force end */ static void gelic_card_disable_rxdmac(struct gelic_card *card) { int status; /* this hvc blocks until the DMA in progress really stopped */ status = lv1_net_stop_rx_dma(bus_id(card), dev_id(card)); if (status) dev_err(ctodev(card), "lv1_net_stop_rx_dma failed, %d\n", status); }
/* set irq_mask */ int gelic_card_set_irq_mask(struct gelic_card *card, u64 mask) { int status; status = lv1_net_set_interrupt_mask(bus_id(card), dev_id(card), mask, 0); if (status) dev_info(ctodev(card), "%s failed %d\n", __func__, status); return status; }
static int gelic_card_set_link_mode(struct gelic_card *card, int mode) { int status; u64 v1, v2; status = lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_SET_NEGOTIATION_MODE, GELIC_LV1_PHY_ETHERNET_0, mode, 0, &v1, &v2); if (status) { pr_info("%s: failed setting negotiation mode %d\n", __func__, status); return -EBUSY; } card->link_mode = mode; return 0; }
/** * gelic_card_kick_txdma - enables TX DMA processing * @card: card structure * @descr: descriptor address to enable TX processing at * */ static int gelic_card_kick_txdma(struct gelic_card *card, struct gelic_descr *descr) { int status = 0; if (card->tx_dma_progress) return 0; if (gelic_descr_get_status(descr) == GELIC_DESCR_DMA_CARDOWNED) { card->tx_dma_progress = 1; status = lv1_net_start_tx_dma(bus_id(card), dev_id(card), descr->bus_addr, 0); if (status) dev_info(ctodev(card), "lv1_net_start_txdma failed," \ "status=%d\n", status); } return status; }
static void gelic_card_get_ether_port_status(struct gelic_card *card, int inform) { u64 v2; struct net_device *ether_netdev; lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_GET_ETH_PORT_STATUS, GELIC_LV1_VLAN_TX_ETHERNET_0, 0, 0, &card->ether_port_status, &v2); if (inform) { ether_netdev = card->netdev[GELIC_PORT_ETHERNET_0]; if (card->ether_port_status & GELIC_LV1_ETHER_LINK_UP) netif_carrier_on(ether_netdev); else netif_carrier_off(ether_netdev); } }
static u32 gelic_net_get_link(struct net_device *netdev) { struct gelic_net_card *card = netdev_priv(netdev); int status; u64 v1, v2; int link; status = lv1_net_control(bus_id(card), dev_id(card), GELIC_NET_GET_ETH_PORT_STATUS, GELIC_NET_PORT, 0, 0, &v1, &v2); if (status) return 0; /* link down */ if (v1 & GELIC_NET_LINK_UP) link = 1; else link = 0; return link; }
static int gelic_net_get_settings(struct net_device *netdev, struct ethtool_cmd *cmd) { struct gelic_net_card *card = netdev_priv(netdev); int status; u64 v1, v2; int speed, duplex; speed = duplex = -1; status = lv1_net_control(bus_id(card), dev_id(card), GELIC_NET_GET_ETH_PORT_STATUS, GELIC_NET_PORT, 0, 0, &v1, &v2); if (status) { /* link down */ } else { if (v1 & GELIC_NET_FULL_DUPLEX) { duplex = DUPLEX_FULL; } else { duplex = DUPLEX_HALF; } if (v1 & GELIC_NET_SPEED_10 ) { speed = SPEED_10; } else if (v1 & GELIC_NET_SPEED_100) { speed = SPEED_100; } else if (v1 & GELIC_NET_SPEED_1000) { speed = SPEED_1000; } } cmd->supported = SUPPORTED_TP | SUPPORTED_Autoneg | SUPPORTED_10baseT_Half | SUPPORTED_10baseT_Full | SUPPORTED_100baseT_Half | SUPPORTED_100baseT_Full | SUPPORTED_1000baseT_Half | SUPPORTED_1000baseT_Full; cmd->advertising = cmd->supported; cmd->speed = speed; cmd->duplex = duplex; cmd->autoneg = AUTONEG_ENABLE; /* always enabled */ cmd->port = PORT_TP; return 0; }
/** * gelic_card_enable_rxdmac - enables the receive DMA controller * @card: card structure * * gelic_card_enable_rxdmac enables the DMA controller by setting RX_DMA_EN * in the GDADMACCNTR register */ static void gelic_card_enable_rxdmac(struct gelic_card *card) { int status; #ifdef DEBUG if (gelic_descr_get_status(card->rx_chain.head) != GELIC_DESCR_DMA_CARDOWNED) { printk(KERN_ERR "%s: status=%x\n", __func__, be32_to_cpu(card->rx_chain.head->dmac_cmd_status)); printk(KERN_ERR "%s: nextphy=%x\n", __func__, be32_to_cpu(card->rx_chain.head->next_descr_addr)); printk(KERN_ERR "%s: head=%p\n", __func__, card->rx_chain.head); } #endif status = lv1_net_start_rx_dma(bus_id(card), dev_id(card), card->rx_chain.head->bus_addr, 0); if (status) dev_info(ctodev(card), "lv1_net_start_rx_dma failed, status=%d\n", status); }
static int ps3_gelic_driver_remove (struct ps3_system_bus_device *dev) { struct gelic_net_card *card = ps3_system_bus_get_driver_data(dev); wait_event(card->waitq, atomic_read(&card->tx_timeout_task_counter) == 0); lv1_net_set_interrupt_status_indicator(bus_id(card), dev_id(card), 0 , 0); unregister_netdev(card->netdev); free_netdev(card->netdev); ps3_system_bus_set_driver_data(dev, NULL); ps3_dma_region_free(dev->d_region); ps3_close_hv_device(dev); return 0; }
/** * gelic_ether_setup_netdev - initialization of net_device * @netdev: net_device structure * @card: card structure * * Returns 0 on success or <0 on failure * * gelic_ether_setup_netdev initializes the net_device structure * and register it. **/ int __devinit gelic_net_setup_netdev(struct net_device *netdev, struct gelic_card *card) { int status; u64 v1, v2; netdev->features = NETIF_F_IP_CSUM; status = lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_GET_MAC_ADDRESS, 0, 0, 0, &v1, &v2); v1 <<= 16; if (status || !is_valid_ether_addr((u8 *)&v1)) { dev_info(ctodev(card), "%s:lv1_net_control GET_MAC_ADDR failed %d\n", __func__, status); return -EINVAL; } memcpy(netdev->dev_addr, &v1, ETH_ALEN); if (card->vlan_required) { netdev->hard_header_len += VLAN_HLEN; /* * As vlan is internally used, * we can not receive vlan packets */ netdev->features |= NETIF_F_VLAN_CHALLENGED; } status = register_netdev(netdev); if (status) { dev_err(ctodev(card), "%s:Couldn't register %s %d\n", __func__, netdev->name, status); return status; } dev_info(ctodev(card), "%s: MAC addr %pM\n", netdev->name, netdev->dev_addr); return 0; }
static int gelic_net_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol) { int status; struct gelic_card *card; u64 v1, v2; if (ps3_compare_firmware_version(2, 2, 0) < 0 || !capable(CAP_NET_ADMIN)) return -EPERM; if (wol->wolopts & ~WAKE_MAGIC) return -EINVAL; card = netdev_card(netdev); if (wol->wolopts & WAKE_MAGIC) { status = lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_SET_WOL, GELIC_LV1_WOL_MAGIC_PACKET, 0, GELIC_LV1_WOL_MP_ENABLE, &v1, &v2); if (status) { pr_info("%s: enabling WOL failed %d\n", __func__, status); status = -EIO; goto done; } status = lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_SET_WOL, GELIC_LV1_WOL_ADD_MATCH_ADDR, 0, GELIC_LV1_WOL_MATCH_ALL, &v1, &v2); if (!status) ps3_sys_manager_set_wol(1); else { pr_info("%s: enabling WOL filter failed %d\n", __func__, status); status = -EIO; } } else { status = lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_SET_WOL, GELIC_LV1_WOL_MAGIC_PACKET, 0, GELIC_LV1_WOL_MP_DISABLE, &v1, &v2); if (status) { pr_info("%s: disabling WOL failed %d\n", __func__, status); status = -EIO; goto done; } status = lv1_net_control(bus_id(card), dev_id(card), GELIC_LV1_SET_WOL, GELIC_LV1_WOL_DELETE_MATCH_ADDR, 0, GELIC_LV1_WOL_MATCH_ALL, &v1, &v2); if (!status) ps3_sys_manager_set_wol(0); else { pr_info("%s: removing WOL filter failed %d\n", __func__, status); status = -EIO; } } done: return status; }
/** * gelic_net_setup_netdev - initialization of net_device * @card: card structure * * Returns 0 on success or <0 on failure * * gelic_net_setup_netdev initializes the net_device structure **/ static int gelic_net_setup_netdev(struct gelic_net_card *card) { struct net_device *netdev = card->netdev; struct sockaddr addr; unsigned int i; int status; u64 v1, v2; SET_MODULE_OWNER(netdev); SET_NETDEV_DEV(netdev, &card->dev->core); spin_lock_init(&card->tx_dma_lock); card->rx_csum = GELIC_NET_RX_CSUM_DEFAULT; gelic_net_setup_netdev_ops(netdev); netdev->features = NETIF_F_IP_CSUM; status = lv1_net_control(bus_id(card), dev_id(card), GELIC_NET_GET_MAC_ADDRESS, 0, 0, 0, &v1, &v2); if (status || !is_valid_ether_addr((u8 *)&v1)) { dev_info(ctodev(card), "%s:lv1_net_control GET_MAC_ADDR failed %d\n", __func__, status); return -EINVAL; } v1 <<= 16; memcpy(addr.sa_data, &v1, ETH_ALEN); memcpy(netdev->dev_addr, addr.sa_data, ETH_ALEN); dev_info(ctodev(card), "MAC addr %02x:%02x:%02x:%02x:%02x:%02x\n", netdev->dev_addr[0], netdev->dev_addr[1], netdev->dev_addr[2], netdev->dev_addr[3], netdev->dev_addr[4], netdev->dev_addr[5]); card->vlan_index = -1; /* no vlan */ for (i = 0; i < GELIC_NET_VLAN_MAX; i++) { status = lv1_net_control(bus_id(card), dev_id(card), GELIC_NET_GET_VLAN_ID, i + 1, /* index; one based */ 0, 0, &v1, &v2); if (status == GELIC_NET_VLAN_NO_ENTRY) { dev_dbg(ctodev(card), "GELIC_VLAN_ID no entry:%d, VLAN disabled\n", status); card->vlan_id[i] = 0; } else if (status) { dev_dbg(ctodev(card), "%s:GELIC_NET_VLAN_ID faild, status=%d\n", __func__, status); card->vlan_id[i] = 0; } else { card->vlan_id[i] = (u32)v1; dev_dbg(ctodev(card), "vlan_id:%d, %lx\n", i, v1); } } if (card->vlan_id[GELIC_NET_VLAN_WIRED - 1]) card->vlan_index = GELIC_NET_VLAN_WIRED - 1; status = register_netdev(netdev); if (status) { dev_err(ctodev(card), "%s:Couldn't register net_device: %d\n", __func__, status); return status; } return 0; }
/** * ps3_gelic_driver_probe - add a device to the control of this driver */ static int ps3_gelic_driver_probe (struct ps3_system_bus_device *dev) { struct gelic_net_card *card = gelic_net_alloc_card(); int result; if (!card) { dev_info(&dev->core, "gelic_net_alloc_card failed\n"); result = -ENOMEM; goto fail_alloc_card; } ps3_system_bus_set_driver_data(dev, card); card->dev = dev; result = ps3_open_hv_device(dev); if (result) { dev_dbg(&dev->core, "ps3_open_hv_device failed\n"); goto fail_open; } result = ps3_dma_region_create(dev->d_region); if (result) { dev_dbg(&dev->core, "ps3_dma_region_create failed(%d)\n", result); BUG_ON("check region type"); goto fail_dma_region; } result = lv1_net_set_interrupt_status_indicator(bus_id(card), dev_id(card), ps3_mm_phys_to_lpar(__pa(&card->irq_status)), 0); if (result) { dev_dbg(&dev->core, "lv1_net_set_interrupt_status_indicator failed: %s\n", ps3_result(result)); result = -EIO; goto fail_status_indicator; } result = gelic_net_setup_netdev(card); if (result) { dev_dbg(&dev->core, "%s:%d: ps3_dma_region_create failed: " "(%d)\n", __func__, __LINE__, result); goto fail_setup_netdev; } return 0; fail_setup_netdev: lv1_net_set_interrupt_status_indicator(bus_id(card), bus_id(card), 0 , 0); fail_status_indicator: ps3_dma_region_free(dev->d_region); fail_dma_region: ps3_close_hv_device(dev); fail_open: ps3_system_bus_set_driver_data(dev, NULL); free_netdev(card->netdev); fail_alloc_card: return result; }