using System;
using System.Collections.Generic;
using System.Linq;
 
public class AchieveTheGoal {
    public enum Direction : int
    {
        Right = 0,
        Left,
        Up,
        Down
    };
    public static int H, W;
    
    public static void Main(){
        string[] line = Console.ReadLine().Split(' ');
        H = int.Parse(line[0]);
        W = int.Parse(line[1]);
        
        int maxCount = 0;
        // マップが二次ではなく一次になるとき
        if (H == 1)
        {
            char[] newline = Console.ReadLine().ToCharArray();
            maxCount = GetMaxCountLine(newline, W);
        }
        else if (W == 1)
        {
            char[] newline = new char[H];
            for (int i = 0 ; i < H; i++)
            {
                newline[i] = Console.ReadLine().ToCharArray()[0];
            }
            maxCount = GetMaxCountLine(newline, H);
        }
        // マップが二次になるとき
        else
        {
            char[,] map = new char[H, W];
    
            // Mapの構築
            for (int i = 0; i < H ; i++ )
            {
                string newline = Console.ReadLine();
                for (int j = 0; j < W ; j++ )
                {
                    map[i, j] = newline.ToCharArray()[j];
                }
            }
            
            // 全通り探索する
            // 探索方法は、幅優先探索
            for (int i = 0; i < W ; i++ )
            {
                for (int j = 0; j < H ; j++ )
                {
                    int treeDepth = GetMaxDepth(map, new Point(i,j));
                    if (maxCount < treeDepth)
                    {
                        maxCount = treeDepth;
                    }
                }
            }
        }
        
        Console.WriteLine(maxCount);
    }
    
    private static int GetMaxCountLine(char[] line, int length)
    {
        int maxCount = 0;
        for (int i = 0 ; i < length ; i++ )
        {
            int currentLength = 0;
            while ((i < length) && (line[i] == '.'))
            {
                currentLength++;
                i++;
            }
            if (maxCount < currentLength-1)
            {
                maxCount = currentLength-1;
            }
        }
        return maxCount;
    }
    
    private static int GetMaxDepth(char[,] map, Point startPoint)
    {
        // スタート地点が壁の場合
        if (map[startPoint.y, startPoint.x] == '#')
        {
            // 長さを0で返す
            return 0;
        }
        
        int maxTreeDepth = 0;
        startPoint.treeDepth = 0;
        Queue<Point> queue = new Queue<Point>();
        queue.Enqueue(startPoint);
        // startPointは既訪問
        Dictionary<string, bool> hasAlreadyVisited = new Dictionary<string, bool>();
        
        while (queue.Count > 0)
        {
            int nextSearchCount = queue.Count;
            for (int i = 0; i < nextSearchCount ; i++)
            {
                Point next = queue.Dequeue();
                string pointID = next.x.ToString() + " " + next.y.ToString();
                // 未訪問の場合のみ続行
                if (!hasAlreadyVisited.ContainsKey(pointID))
                {
                    hasAlreadyVisited[pointID] = true;
                    VisitNextPoint(map, next, queue);
                    maxTreeDepth = next.treeDepth;
                }
            }
        }
        return maxTreeDepth;
    }
    
    private static void VisitNextPoint(char[,] map, Point p, Queue<Point> queue)
    {
        if (MoveCheck(map, p, (int)Direction.Right)) 
        {
            Point rightPoint = new Point(p.x+1, p.y);
            rightPoint.treeDepth = p.treeDepth + 1;
            queue.Enqueue(rightPoint);
        }
        if (MoveCheck(map, p, (int)Direction.Left))
        {
            Point leftPoint = new Point(p.x-1, p.y);
            leftPoint.treeDepth = p.treeDepth + 1;
            queue.Enqueue(leftPoint);
        }
        if (MoveCheck(map, p, (int)Direction.Up))
        {
            Point upPoint = new Point(p.x, p.y-1);
            upPoint.treeDepth = p.treeDepth + 1;
            queue.Enqueue(upPoint);
        }
        if (MoveCheck(map, p, (int)Direction.Down))
        {
            Point downPoint = new Point(p.x, p.y+1);
            downPoint.treeDepth = p.treeDepth + 1;
            queue.Enqueue(downPoint);
        }
    }
    
    private static bool MoveCheck(char[,] map, Point p, int dir)
    {
        if (dir == (int)Direction.Right)
        {
            if (p.x+1 >= W) 
            {
                return false;
            }
            else
            {
                if (map[p.y, p.x+1] == '.')
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
        else if (dir == (int)Direction.Left)
        {
            if (p.x-1 < 0) 
            {
                return false;
            }
            else
            {
                if (map[p.y, p.x-1] == '.')
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
        else if (dir == (int)Direction.Up)
        {
            if (p.y-1 < 0) 
            {
                return false;
            }
            else
            {
                if (map[p.y-1, p.x] == '.')
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
        else if (dir == (int)Direction.Down)
        {
            if (p.y+1 >= H) 
            {
                return false;
            }
            else
            {
                if (map[p.y+1, p.x] == '.')
                {
                    return true;
                }
                else
                {
                    return false;
                }
            }
        }
        return false;
    }
}

public class Point {
    public int x, y;
    public int treeDepth;
    public Point(int x, int y)
    {
        this.x = x;
        this.y = y;
    }
}

Measured memory_bytes: 29336