diff options
Diffstat (limited to 'drivers/ntb/ntb_hw.c')
| -rw-r--r-- | drivers/ntb/ntb_hw.c | 42 |
1 files changed, 37 insertions, 5 deletions
diff --git a/drivers/ntb/ntb_hw.c b/drivers/ntb/ntb_hw.c index 80505aeecf9e..170e8e60cdb7 100644 --- a/drivers/ntb/ntb_hw.c +++ b/drivers/ntb/ntb_hw.c | |||
| @@ -141,6 +141,24 @@ void ntb_unregister_event_callback(struct ntb_device *ndev) | |||
| 141 | ndev->event_cb = NULL; | 141 | ndev->event_cb = NULL; |
| 142 | } | 142 | } |
| 143 | 143 | ||
| 144 | static void ntb_irq_work(unsigned long data) | ||
| 145 | { | ||
| 146 | struct ntb_db_cb *db_cb = (struct ntb_db_cb *)data; | ||
| 147 | int rc; | ||
| 148 | |||
| 149 | rc = db_cb->callback(db_cb->data, db_cb->db_num); | ||
| 150 | if (rc) | ||
| 151 | tasklet_schedule(&db_cb->irq_work); | ||
| 152 | else { | ||
| 153 | struct ntb_device *ndev = db_cb->ndev; | ||
| 154 | unsigned long mask; | ||
| 155 | |||
| 156 | mask = readw(ndev->reg_ofs.ldb_mask); | ||
| 157 | clear_bit(db_cb->db_num * ndev->bits_per_vector, &mask); | ||
| 158 | writew(mask, ndev->reg_ofs.ldb_mask); | ||
| 159 | } | ||
| 160 | } | ||
| 161 | |||
| 144 | /** | 162 | /** |
| 145 | * ntb_register_db_callback() - register a callback for doorbell interrupt | 163 | * ntb_register_db_callback() - register a callback for doorbell interrupt |
| 146 | * @ndev: pointer to ntb_device instance | 164 | * @ndev: pointer to ntb_device instance |
| @@ -155,7 +173,7 @@ void ntb_unregister_event_callback(struct ntb_device *ndev) | |||
| 155 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. | 173 | * RETURNS: An appropriate -ERRNO error value on error, or zero for success. |
| 156 | */ | 174 | */ |
| 157 | int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, | 175 | int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, |
| 158 | void *data, void (*func)(void *data, int db_num)) | 176 | void *data, int (*func)(void *data, int db_num)) |
| 159 | { | 177 | { |
| 160 | unsigned long mask; | 178 | unsigned long mask; |
| 161 | 179 | ||
| @@ -166,6 +184,10 @@ int ntb_register_db_callback(struct ntb_device *ndev, unsigned int idx, | |||
| 166 | 184 | ||
| 167 | ndev->db_cb[idx].callback = func; | 185 | ndev->db_cb[idx].callback = func; |
| 168 | ndev->db_cb[idx].data = data; | 186 | ndev->db_cb[idx].data = data; |
| 187 | ndev->db_cb[idx].ndev = ndev; | ||
| 188 | |||
| 189 | tasklet_init(&ndev->db_cb[idx].irq_work, ntb_irq_work, | ||
| 190 | (unsigned long) &ndev->db_cb[idx]); | ||
| 169 | 191 | ||
| 170 | /* unmask interrupt */ | 192 | /* unmask interrupt */ |
| 171 | mask = readw(ndev->reg_ofs.ldb_mask); | 193 | mask = readw(ndev->reg_ofs.ldb_mask); |
| @@ -194,6 +216,8 @@ void ntb_unregister_db_callback(struct ntb_device *ndev, unsigned int idx) | |||
| 194 | set_bit(idx * ndev->bits_per_vector, &mask); | 216 | set_bit(idx * ndev->bits_per_vector, &mask); |
| 195 | writew(mask, ndev->reg_ofs.ldb_mask); | 217 | writew(mask, ndev->reg_ofs.ldb_mask); |
| 196 | 218 | ||
| 219 | tasklet_disable(&ndev->db_cb[idx].irq_work); | ||
| 220 | |||
| 197 | ndev->db_cb[idx].callback = NULL; | 221 | ndev->db_cb[idx].callback = NULL; |
| 198 | } | 222 | } |
| 199 | 223 | ||
| @@ -955,12 +979,16 @@ static irqreturn_t bwd_callback_msix_irq(int irq, void *data) | |||
| 955 | { | 979 | { |
| 956 | struct ntb_db_cb *db_cb = data; | 980 | struct ntb_db_cb *db_cb = data; |
| 957 | struct ntb_device *ndev = db_cb->ndev; | 981 | struct ntb_device *ndev = db_cb->ndev; |
| 982 | unsigned long mask; | ||
| 958 | 983 | ||
| 959 | dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, | 984 | dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, |
| 960 | db_cb->db_num); | 985 | db_cb->db_num); |
| 961 | 986 | ||
| 962 | if (db_cb->callback) | 987 | mask = readw(ndev->reg_ofs.ldb_mask); |
| 963 | db_cb->callback(db_cb->data, db_cb->db_num); | 988 | set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); |
| 989 | writew(mask, ndev->reg_ofs.ldb_mask); | ||
| 990 | |||
| 991 | tasklet_schedule(&db_cb->irq_work); | ||
| 964 | 992 | ||
| 965 | /* No need to check for the specific HB irq, any interrupt means | 993 | /* No need to check for the specific HB irq, any interrupt means |
| 966 | * we're connected. | 994 | * we're connected. |
| @@ -976,12 +1004,16 @@ static irqreturn_t xeon_callback_msix_irq(int irq, void *data) | |||
| 976 | { | 1004 | { |
| 977 | struct ntb_db_cb *db_cb = data; | 1005 | struct ntb_db_cb *db_cb = data; |
| 978 | struct ntb_device *ndev = db_cb->ndev; | 1006 | struct ntb_device *ndev = db_cb->ndev; |
| 1007 | unsigned long mask; | ||
| 979 | 1008 | ||
| 980 | dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, | 1009 | dev_dbg(&ndev->pdev->dev, "MSI-X irq %d received for DB %d\n", irq, |
| 981 | db_cb->db_num); | 1010 | db_cb->db_num); |
| 982 | 1011 | ||
| 983 | if (db_cb->callback) | 1012 | mask = readw(ndev->reg_ofs.ldb_mask); |
| 984 | db_cb->callback(db_cb->data, db_cb->db_num); | 1013 | set_bit(db_cb->db_num * ndev->bits_per_vector, &mask); |
| 1014 | writew(mask, ndev->reg_ofs.ldb_mask); | ||
| 1015 | |||
| 1016 | tasklet_schedule(&db_cb->irq_work); | ||
| 985 | 1017 | ||
| 986 | /* On Sandybridge, there are 16 bits in the interrupt register | 1018 | /* On Sandybridge, there are 16 bits in the interrupt register |
| 987 | * but only 4 vectors. So, 5 bits are assigned to the first 3 | 1019 | * but only 4 vectors. So, 5 bits are assigned to the first 3 |
