ath5k: fix enabling 5/10 mhz channel bandwidth support
[openwrt.git] / package / kernel / mac80211 / patches / 440-ath5k_channel_bw_debugfs.patch
1 This adds a bwmode debugfs file which can be used to set alternate
2 channel operating bandwidths.  Only tested with AR5413 and only at
3 5 and 20 mhz channels.
4
5 Signed-off-by: Pat Erley <pat-lkml at erley.org>
6 ---
7 Other devices will need to be added to the switch in  write_file_bwmode
8
9 drivers/net/wireless/ath/ath5k/debug.c |   86 ++++++++++++++++++++++++++++++++
10  1 files changed, 86 insertions(+), 0 deletions(-)
11
12 --- a/drivers/net/wireless/ath/ath5k/debug.c
13 +++ b/drivers/net/wireless/ath/ath5k/debug.c
14 @@ -821,6 +821,97 @@ static const struct file_operations fops
15         .llseek = default_llseek,
16  };
17  
18 +/* debugfs: bwmode */
19 +
20 +static ssize_t read_file_bwmode(struct file *file, char __user *user_buf,
21 +                                  size_t count, loff_t *ppos)
22 +{
23 +       struct ath5k_hw *ah = file->private_data;
24 +       char buf[15];
25 +       unsigned int len = 0;
26 +
27 +       int cur_ah_bwmode = ah->ah_bwmode_debug;
28 +
29 +#define print_selected(MODE, LABEL) \
30 +       if (cur_ah_bwmode == MODE) \
31 +               len += snprintf(buf+len, sizeof(buf)-len, "[%s]", LABEL); \
32 +       else \
33 +               len += snprintf(buf+len, sizeof(buf)-len, "%s", LABEL); \
34 +       len += snprintf(buf+len, sizeof(buf)-len, " ");
35 +
36 +       print_selected(AR5K_BWMODE_5MHZ, "5");
37 +       print_selected(AR5K_BWMODE_10MHZ, "10");
38 +       print_selected(AR5K_BWMODE_DEFAULT, "20");
39 +       print_selected(AR5K_BWMODE_40MHZ, "40");
40 +#undef print_selected
41 +
42 +       len += snprintf(buf+len, sizeof(buf)-len, "\n");
43 +
44 +       return simple_read_from_buffer(user_buf, count, ppos, buf, len);
45 +}
46 +
47 +static ssize_t write_file_bwmode(struct file *file,
48 +                                const char __user *userbuf,
49 +                                size_t count, loff_t *ppos)
50 +{
51 +       struct ath5k_hw *ah = file->private_data;
52 +       char buf[3];
53 +       int bw = 20;
54 +       int tobwmode = AR5K_BWMODE_DEFAULT;
55 +
56 +       if (copy_from_user(buf, userbuf, min(count, sizeof(buf))))
57 +               return -EFAULT;
58 +
59 +       /* TODO: Add check for active interface */
60 +
61 +       if(strncmp(buf, "5", 1) == 0 ) {
62 +               tobwmode = AR5K_BWMODE_5MHZ;
63 +               bw = 5;
64 +       } else if ( strncmp(buf, "10", 2) == 0 ) {
65 +               tobwmode = AR5K_BWMODE_10MHZ;
66 +               bw = 10;
67 +       } else if ( strncmp(buf, "20", 2) == 0 ) {
68 +               tobwmode = AR5K_BWMODE_DEFAULT;
69 +               bw = 20;
70 +       } else if ( strncmp(buf, "40", 2) == 0 ) {
71 +               tobwmode = AR5K_BWMODE_40MHZ;
72 +               bw = 40;
73 +       } else
74 +               return -EINVAL;
75 +
76 +       ATH5K_INFO(ah, "Changing to %imhz channel width[%i]\n",
77 +               bw, tobwmode);
78 +
79 +       switch (ah->ah_radio) {
80 +       /* TODO: only define radios that actually support 5/10mhz channels */
81 +       case AR5K_RF5413:
82 +       case AR5K_RF5110:
83 +       case AR5K_RF5111:
84 +       case AR5K_RF5112:
85 +       case AR5K_RF2413:
86 +       case AR5K_RF2316:
87 +       case AR5K_RF2317:
88 +       case AR5K_RF2425:
89 +               if(ah->ah_bwmode_debug != tobwmode) {
90 +                       mutex_lock(&ah->lock);
91 +                       ah->ah_bwmode = tobwmode;
92 +                       ah->ah_bwmode_debug = tobwmode;
93 +                       mutex_unlock(&ah->lock);
94 +               }
95 +               break;
96 +       default:
97 +               return -EOPNOTSUPP;
98 +       }
99 +       return count;
100 +}
101 +
102 +static const struct file_operations fops_bwmode = {
103 +       .read = read_file_bwmode,
104 +       .write = write_file_bwmode,
105 +       .open = simple_open,
106 +       .owner = THIS_MODULE,
107 +       .llseek = default_llseek,
108 +};
109  
110  /* debugfs: queues etc */
111  
112 @@ -914,6 +1005,9 @@ ath5k_debug_init_device(struct ath5k_hw 
113         debugfs_create_file("beacon", S_IWUSR | S_IRUSR, phydir, ah,
114                             &fops_beacon);
115  
116 +       debugfs_create_file("bwmode", S_IWUSR | S_IRUSR, phydir, ah,
117 +                           &fops_bwmode);
118 +
119         debugfs_create_file("reset", S_IWUSR, phydir, ah, &fops_reset);
120  
121         debugfs_create_file("antenna", S_IWUSR | S_IRUSR, phydir, ah,
122 --- a/drivers/net/wireless/ath/ath5k/ath5k.h
123 +++ b/drivers/net/wireless/ath/ath5k/ath5k.h
124 @@ -1369,6 +1369,7 @@ struct ath5k_hw {
125         u8                      ah_coverage_class;
126         bool                    ah_ack_bitrate_high;
127         u8                      ah_bwmode;
128 +       u8                      ah_bwmode_debug;
129         bool                    ah_short_slot;
130  
131         /* Antenna Control */
132 --- a/drivers/net/wireless/ath/ath5k/base.c
133 +++ b/drivers/net/wireless/ath/ath5k/base.c
134 @@ -466,6 +466,9 @@ ath5k_chan_set(struct ath5k_hw *ah, stru
135                 return -EINVAL;
136         }
137  
138 +       if (ah->ah_bwmode_debug != AR5K_BWMODE_DEFAULT)
139 +               ah->ah_bwmode = ah->ah_bwmode_debug;
140 +
141         /*
142          * To switch channels clear any pending DMA operations;
143          * wait long enough for the RX fifo to drain, reset the