Code runs Speed Test CLI using the python wrapper and then stores values within CSV
Don't use globals. E.g., you refer to df and df2 in csv_upload, why not make them parameters?
Use the standard if __name__ == '__main__': guard around the script's main body.
It's common to just accept a flat file path, and expect the calling code to perform any os.path.join in the creation of said path.
"upload" sounds like network activity, but you're saving the data to disk. This should probably follow a more typical naming scheme of to_csv or save or dump or something of that sort.
This seems like a prime candidate for being a class.


I'd suggest something like the following:

import speedtest
import pandas as pd
import os


class MySpeedtest:
    def __init__(servers, initial_data_path=None):
        # Initial Speedtest variables
        self.s = speedtest.Speedtest()
        self.servers = servers

        if initial_data_path is not None:
            self.df = pd.read_csv(initial_data_path)
        else:
            self.df = pd.DataFrame()

    def run_test(self):
        """Makes use of the speed-test-cli python wrapper
        to get speed test data and returns in a dictionary"""
        self.s.get_servers(self.servers)
        self.s.get_best_server()
        self.s.download()
        self.s.upload()
        self.s.results.share()
        results_dict = self.s.results.dict()
        self.df.append(pd.io.json.json_normalize(results_dict))

    @staticmethod
    def convert_mbps(arg):
        return arg / 1000000
        # Actually, this should probably be "arg / (2**20)"
        # 1 MB = 2**20 B

    def to_csv(self, path):
        """Attempts to append a csv file and, if none
        exists, creates one in a specified path"""
        self.df.to_csv(path, index=False)


if __name__ == '__main__':
    # TODO: populate a list of servers, define localpath/filepath/filename
    tester = MySpeedtest(servers, localpath)
    tester.run_test()
    tester.to_csv(os.path.join(filepath, filename))